more_convert_derive/
lib.rs

1#![deny(
2    clippy::unwrap_used,
3    clippy::expect_used,
4    clippy::panic,
5    clippy::print_stdout,
6    clippy::print_stderr
7)]
8
9macro_rules! use_internal {
10    ($internal:path, $input:ident) => {
11        $internal(syn::parse_macro_input!($input as syn::DeriveInput))
12            .unwrap_or_else(syn::Error::into_compile_error)
13            .into()
14    };
15}
16
17/// Automatically implements [`std::convert::From`] for repr from enum.
18/// And implements [`std::convert::TryFrom`] for enum from repr.
19/// or implements [`std::convert::From`] for enum from repr.
20///
21/// # Where to use:
22///  - Managing Type
23///  - Easy to understand constants
24///
25/// # Note:
26///  - require `#[repr(u8)]` or `#[repr(u16)]` or ...
27///  - default is require explicit
28///  - #[enum_repr(default)] is special attribute on variant
29///
30/// # Enum Attribute:
31///  - serde: automatically implements [`serde::Serialize`] and [`serde::Deserialize`]
32///  - implicit: make it less explicit
33///
34/// # Variant Attribute:
35///  - default: Sets the fallback value if none of the others apply.
36///    this attribute is required to be used only once or not at all
37///    if this attribute is not used, it will be impl [`std::convert::TryFrom`]
38///    used, it will be impl [`std::convert::From`]
39///
40/// # Examples
41///
42/// ## Normal
43///
44/// ```rust
45/// # mod more_convert {
46/// #   pub use more_convert_derive::EnumRepr;
47/// #   include!("../../more-convert/src/enum_repr.rs");
48/// # }
49/// use more_convert::EnumRepr;
50/// #[derive(EnumRepr, Clone, Copy, Debug, PartialEq)]
51/// #[repr(u8)]
52/// pub enum Test {
53///     Zero = 0,
54///     Three = 3,
55///     Four = 4,
56/// }
57///
58/// assert_eq!(0u8, Test::Zero.into());
59/// assert_eq!(3u8, Test::Three.into());
60/// assert_eq!(4u8, Test::Four.into());
61///
62/// assert_eq!(0u8.try_into(), Ok(Test::Zero));
63/// assert_eq!(3u8.try_into(), Ok(Test::Three));
64/// assert_eq!(4u8.try_into(), Ok(Test::Four));
65///
66/// assert_eq!(TryInto::<Test>::try_into(1u8).unwrap_err(), more_convert::TryFromEnumReprError::new("Test".to_string(), 1.to_string()));
67/// ```
68///
69/// ## serde
70///
71/// ```rust
72/// # mod more_convert {
73/// #   pub use more_convert_derive::EnumRepr;
74/// #   include!("../../more-convert/src/enum_repr.rs");
75/// # }
76/// use more_convert::EnumRepr;
77/// #[derive(EnumRepr, Clone, Copy, Debug, PartialEq)]
78/// #[repr(u8)]
79/// #[enum_repr(serde)]
80/// pub enum Test {
81///     Zero = 0,
82///     Three = 3,
83///     Four = 4,
84/// }
85///
86///
87/// assert_eq!(serde_json::to_string(&Test::Zero).unwrap(), "0");
88/// assert_eq!(serde_json::to_string(&Test::Three).unwrap(), "3");
89/// assert_eq!(serde_json::to_string(&Test::Four).unwrap(), "4");
90///
91/// assert_eq!(serde_json::from_str::<Test>("0").unwrap(), Test::Zero);
92/// assert_eq!(serde_json::from_str::<Test>("3").unwrap(), Test::Three);
93/// assert_eq!(serde_json::from_str::<Test>("4").unwrap(), Test::Four);
94///
95/// assert_eq!(serde_json::from_str::<Test>("1").unwrap_err().to_string(), String::from("Failed to convert value 1 to enum Test"));
96/// ```
97/// ## implicit
98///
99/// ```rust
100/// # mod more_convert {
101/// #   pub use more_convert_derive::EnumRepr;
102/// #   include!("../../more-convert/src/enum_repr.rs");
103/// # }
104/// use more_convert::EnumRepr;
105/// #[derive(EnumRepr, Clone, Copy, Debug, PartialEq)]
106/// #[repr(u8)]
107/// #[enum_repr(implicit)]
108/// pub enum Test {
109///     Zero,
110///     Three = 3,
111///     Four,
112/// }
113///
114/// assert_eq!(0u8, Test::Zero.into());
115/// assert_eq!(3u8, Test::Three.into());
116/// assert_eq!(4u8, Test::Four.into());
117///
118/// assert_eq!(0u8.try_into(), Ok(Test::Zero));
119/// assert_eq!(3u8.try_into(), Ok(Test::Three));
120/// assert_eq!(4u8.try_into(), Ok(Test::Four));
121///
122/// assert_eq!(TryInto::<Test>::try_into(1u8).unwrap_err(), more_convert::TryFromEnumReprError::new("Test".to_string(), 1.to_string()));
123/// ```
124///
125/// ## default
126///
127/// ```rust
128/// # mod more_convert {
129/// #   pub use more_convert_derive::EnumRepr;
130/// #   include!("../../more-convert/src/enum_repr.rs");
131/// # }
132/// use more_convert::EnumRepr;
133/// #[derive(EnumRepr, Clone, Copy, Debug, PartialEq)]
134/// #[repr(u8)]
135/// pub enum Test {
136///     Zero = 0,
137///     One = 1,
138///     #[enum_repr(default)]
139///     Two = 2,
140/// }
141///
142/// assert_eq!(0u8, Test::Zero.into());
143/// assert_eq!(1u8, Test::One.into());
144/// assert_eq!(2u8, Test::Two.into());
145///
146/// // Invalid values return the default variant
147/// assert_eq!(Test::Two, 255u8.into());
148///
149#[proc_macro_derive(EnumRepr, attributes(enum_repr))]
150pub fn derive_enum_repr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
151    use_internal!(more_convert_derive_internal::derive_enum_repr, input)
152}
153
154/// Automatically implements [`std::convert::From`] on structs.
155///
156/// # Who uses it:
157///   - When you are using the architectural
158///   - Those who find the implementation of from and into cumbersome.
159///
160/// # Struct Attribute #[convert]:
161///   - into: `impl From<#self> for #into_struct { /* auto gen */}`
162///   - from: `impl From<#from_struct> for #self { /* auto gen */}`
163///   - from_into: impl from and into
164///
165/// # Struct Attribute #[generate]:
166///   - example `#[generate(B(is_negative = value.sample.is_negative()))]`
167///     generate is used to generate the field value of the target struct
168///
169/// # Field Attribute:
170///   - filter of target: (option, default apply all)
171///     - example `#[convert(from(A,B),ignore,..)]`, this field ignored in A and B
172///     - apply priority: from and into > from_into > all
173///   - ignore: ignore this field
174///   - rename: rename this field
175///   - group of map: map this field (Choose one of these)
176///     > default: `#field_name.into()`
177///     - map: replace expr
178///     - map_field: Process and pass field data
179///     - map_struct: Create data from struct references
180///
181/// # Examples
182///
183/// ## Normal
184///
185/// ```rust
186/// # mod more_convert {
187/// #   pub use more_convert_derive::Convert;
188/// # }
189/// use more_convert::Convert;
190/// #[derive(Convert)]
191/// #[convert(into(B))]
192/// pub struct A {
193///     pub normal: u8,
194///     // auto into of inner
195///     pub opt: Option<u8>,
196///     // auto into of inner
197///     pub vec: Vec<u8>,
198/// }
199///
200/// pub struct B {
201///     normal: u16,
202///     opt: Option<u16>,
203///     vec: Vec<u16>,
204/// }
205///
206/// let a = A {
207///     normal: 0u8,
208///     opt: Some(1u8),
209///     vec: vec![2u8, 3u8],
210/// };
211///
212/// let b: B = a.into();
213///
214/// assert_eq!(b.normal, 0u16);
215/// assert_eq!(b.opt, Some(1u16));
216/// assert_eq!(b.vec, vec![2u16, 3u16]);
217/// ```
218///
219/// ## Reanem
220///
221/// ```rust
222/// # mod more_convert {
223/// #   pub use more_convert_derive::Convert;
224/// # }
225/// use more_convert::Convert;
226/// #[derive(Convert)]
227/// #[convert(into(B))]
228/// pub struct A {
229///     #[convert(rename = "sample")]
230///     hey: String,
231/// }
232///
233/// pub struct B {
234///     sample: String,
235/// }
236///
237/// let a = A {
238///     hey: "hello".to_string(),
239/// };
240///
241/// let b: B = a.into();
242///
243/// assert_eq!(b.sample, "hello");
244/// ```
245///
246/// ## Map
247///
248/// ```rust
249/// # mod more_convert {
250/// #   pub use more_convert_derive::Convert;
251/// # }
252/// use more_convert::Convert;
253/// #[derive(Convert)]
254/// #[convert(into(B))]
255/// pub struct A {
256///     // value's type is `A`
257///     // The reason for the `value` is because of the From trait's args
258///     #[convert(map = value.map.to_string())]
259///     map: u8,
260///     #[convert(map_field = map_field)]
261///     map_field: u8,
262///     #[convert(map_struct = map_struct)]
263///     map_struct: u8,
264/// }
265///
266/// fn map_field(map_field: u8) -> String {
267///     map_field.to_string()
268/// }
269///
270/// fn map_struct(a: &A) -> String {
271///     a.map_struct.to_string()
272/// }
273///
274/// pub struct B {
275///     map: String,
276///     map_field: String,
277///     map_struct: String,
278/// }
279///
280/// let a = A {
281///     map: 1,
282///     map_field: 2,
283///     map_struct: 3,
284/// };
285///
286/// let b: B = a.into();
287///
288/// assert_eq!(b.map, "1");
289/// assert_eq!(b.map_field, "2");
290/// assert_eq!(b.map_struct, "3");
291/// ```
292///
293/// ## from_into and filter
294///
295/// ```rust
296/// # mod more_convert {
297/// #   pub use more_convert_derive::Convert;
298/// # }
299/// use more_convert::Convert;
300///
301/// #[derive(Convert)]
302/// #[convert(from_into(B))]
303/// pub struct A {
304///     pub sample: u8,
305///
306///     #[convert(from(B), map = Default::default())]
307///     #[convert(into(B), ignore)]
308///     pub hey: u16,
309/// }
310///
311/// pub struct B {
312///     sample: u8,
313/// }
314///
315/// let b = B { sample: 1 };
316/// let a: A = b.into();
317/// assert_eq!(a.sample, 1u8);
318/// assert_eq!(a.hey, 0u16);
319/// ```
320///
321/// ## #[genearate]
322///
323/// ```rust
324/// # mod more_convert {
325/// #   pub use more_convert_derive::Convert;
326/// # }
327/// use more_convert::Convert;
328///
329/// #[derive(Convert)]
330/// #[convert(into(B))]
331/// #[generate(B(is_negative = value.sample.is_negative()))]
332/// pub struct A {
333///     pub sample: i8,
334/// }
335///
336/// pub struct B {
337///     pub sample: i8,
338///     pub is_negative: bool,
339/// }
340///
341/// let a = A { sample: -1 };
342/// let b: B = a.into();
343///
344/// assert_eq!(b.sample, -1);
345/// assert!(b.is_negative);
346/// ```
347///
348#[proc_macro_derive(Convert, attributes(convert, generate))]
349pub fn derive_convert(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
350    use_internal!(more_convert_derive_internal::derive_convert, input)
351}
352
353/// Automatically implements [`more_convert::VariantName`] on enum
354///
355/// # Where to use:
356///   - Only want the kind
357///
358/// # Note:
359///   - prefix and suffix are applied after rename_all
360///
361/// # EnumAttribute:
362///   - rename_all: apply rule to field name
363///     - default is "none"
364///     - The possible values are ("lowercase", "UPPERCASE", "PascalCase", "camelCase",
365///       "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE")
366///   - prefix: add prefix to field name
367///   - suffix: add suffix to field name
368///
369/// # Variant Attribute:
370///  - rename: rename field, (prefix, suffix and rename_all are not applied)
371///  - nest: call VariantName on the first field of the variant
372///
373/// # Examples
374///
375/// ## Normal
376///
377/// ```rust
378/// # mod more_convert {
379/// #   pub use more_convert_derive::VariantName;
380/// #   include!("../../more-convert/src/variant_name.rs");
381/// # }
382/// use more_convert::VariantName;
383///
384/// #[derive(VariantName)]
385/// pub enum Error {
386///   InvalidCode,
387///   ServerError,
388/// }
389///
390/// assert_eq!("InvalidCode", Error::InvalidCode.variant_name());
391/// assert_eq!("ServerError", Error::ServerError.variant_name());
392/// ```
393///
394/// ## rename and rename_all
395///
396/// ```rust
397/// # mod more_convert {
398/// #   pub use more_convert_derive::VariantName;
399/// #   include!("../../more-convert/src/variant_name.rs");
400/// # }
401/// use more_convert::VariantName;
402///
403/// #[derive(VariantName)]
404/// #[variant_name(rename_all = "snake_case")]
405/// pub enum Error {
406///   InvalidCode,
407///   ServerError,
408///   #[variant_name(rename = "NotFound")]
409///   NotFoundError,
410/// }
411///
412/// assert_eq!("invalid_code", Error::InvalidCode.variant_name());
413/// assert_eq!("server_error", Error::ServerError.variant_name());
414/// assert_eq!("NotFound", Error::NotFoundError.variant_name());
415/// ```
416///
417/// ## prefix and suffix
418/// ```rust
419/// # mod more_convert {
420/// #   pub use more_convert_derive::VariantName;
421/// #   include!("../../more-convert/src/variant_name.rs");
422/// # }
423/// use more_convert::VariantName;
424///
425/// #[derive(VariantName)]
426/// #[variant_name(prefix = "Error", suffix  = "What")]
427/// pub enum Error {
428///  InvalidCode,
429///  ServerError,
430/// }
431///
432/// assert_eq!("ErrorInvalidCodeWhat", Error::InvalidCode.variant_name());
433/// assert_eq!("ErrorServerErrorWhat", Error::ServerError.variant_name());
434/// ```
435///
436/// ## nest
437/// ```rust
438/// # mod more_convert {
439/// #   pub use more_convert_derive::VariantName;
440/// #   include!("../../more-convert/src/variant_name.rs");
441/// # }
442/// use more_convert::VariantName;
443///
444/// #[derive(VariantName)]
445/// #[variant_name(prefix = "Inner")]
446/// pub enum Inner {
447///     A,
448///     B,
449/// }
450///
451/// #[derive(VariantName)]
452/// pub enum TestVariantName {
453///     InvalidCode,
454///
455///     #[variant_name(nest)]
456///     Inner(Inner),
457/// }
458///
459/// assert_eq!("InvalidCode", TestVariantName::InvalidCode.variant_name());
460///
461/// assert_eq!("InnerA", TestVariantName::Inner(Inner::A).variant_name());
462/// assert_eq!("InnerB", TestVariantName::Inner(Inner::B).variant_name());
463/// ```
464///
465/// ## without_trait
466/// ```rust
467/// # mod more_convert {
468/// #   pub use more_convert_derive::VariantName;
469/// #   include!("../../more-convert/src/variant_name.rs");
470/// # }
471/// #[derive(more_convert::VariantName)]
472/// #[variant_name(without_trait)]
473/// pub enum Error {
474///  InvalidCode,
475///  ServerError,
476/// }
477///
478/// // call at const
479/// const INVALID_CODE: &str = Error::InvalidCode.variant_name();
480///
481/// mod test {
482///     fn something() {
483///         // not depend on VariantName trait
484///         crate::Error::InvalidCode.variant_name();
485///     }
486/// }
487///
488/// # fn main() {}
489/// ```
490#[proc_macro_derive(VariantName, attributes(variant_name))]
491pub fn derive_variant_name(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
492    use_internal!(more_convert_derive_internal::derive_variant_name, input)
493}
494
495/// Automatically generate a `COUNT` and `VARIANTS` constant for enum.
496///
497/// # Where to use:
498/// - When you want to all variants of enum
499/// - When you want to count of enum
500///
501/// # Note:
502/// - `VARIANTS` order is same as enum definition order.
503///   not calculate the discriminant value.
504///
505///
506/// # EnumAttribute: none
507/// # Variant Attribute: none
508///
509/// # Examples
510///
511/// ## Normal
512///
513/// ```rust
514/// # mod more_convert {
515/// #   pub use more_convert_derive::EnumArray;
516/// # }
517/// use more_convert::EnumArray;
518/// #[derive(EnumArray, Clone, Copy, Debug, PartialEq)]
519/// pub enum Test {
520///     Zero = 1,
521///     Three = 3,
522///     Two = 2,
523/// }
524///
525/// assert_eq!(Test::COUNT, 3usize);
526/// // order is same as enum definition order.
527/// // not calculate the discriminant value.
528/// assert_eq!(Test::VARIANTS, &[Test::Zero, Test::Three, Test::Two]);
529/// ```
530#[proc_macro_derive(EnumArray, attributes(enum_array))]
531pub fn derive_enum_array(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
532    use_internal!(more_convert_derive_internal::derive_enum_array, input)
533}