more_convert_derive/
lib.rs

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