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}