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}