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