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}