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:
111/// - group of convert: (Choose one of these)
112/// - into: `impl From<#self> for #into_struct { /* auto gen */}`
113/// - from: `impl From<#from_struct> for #self { /* auto gen */}`
114///
115/// # Field Attribute:
116/// - ignore: ignore this field
117/// - rename: rename this field
118/// - group of map: map this field (Choose one of these)
119/// - map: replace expr
120/// - map_field: Process and pass field data
121/// - map_struct: Create data from struct references
122///
123/// # Examples
124///
125/// ## Normal
126///
127/// ```rust
128/// use more_convert::Convert;
129/// #[derive(Convert)]
130/// #[convert(into(B))]
131/// pub struct A {
132/// pub normal: u8,
133/// // auto into of inner
134/// pub opt: Option<u8>,
135/// // auto into of inner
136/// pub vec: Vec<u8>,
137/// }
138///
139/// pub struct B {
140/// normal: u16,
141/// opt: Option<u16>,
142/// vec: Vec<u16>,
143/// }
144///
145/// let a = A {
146/// normal: 0u8,
147/// opt: Some(1u8),
148/// vec: vec![2u8, 3u8],
149/// };
150///
151/// let b: B = a.into();
152///
153/// assert_eq!(b.normal, 0u16);
154/// assert_eq!(b.opt, Some(1u16));
155/// assert_eq!(b.vec, vec![2u16, 3u16]);
156/// ```
157///
158/// ## Reanem
159///
160/// ```rust
161/// use more_convert::Convert;
162/// #[derive(Convert)]
163/// #[convert(into(B))]
164/// pub struct A {
165/// #[convert(rename = "sample")]
166/// hey: String,
167/// }
168///
169/// pub struct B {
170/// sample: String,
171/// }
172///
173/// let a = A {
174/// hey: "hello".to_string(),
175/// };
176///
177/// let b: B = a.into();
178///
179/// assert_eq!(b.sample, "hello");
180/// ```
181///
182/// ## Map
183///
184/// ```rust
185/// use more_convert::Convert;
186/// #[derive(Convert)]
187/// #[convert(into(B))]
188/// pub struct A {
189/// // value's type is `A`
190/// // The reason for the `value` is because of the From trait's args
191/// #[convert(map = value.map.to_string())]
192/// map: u8,
193/// #[convert(map_field = map_field)]
194/// map_field: u8,
195/// #[convert(map_struct = map_struct)]
196/// map_struct: u8,
197/// }
198///
199/// fn map_field(map_field: u8) -> String {
200/// map_field.to_string()
201/// }
202///
203/// fn map_struct(a: &A) -> String {
204/// a.map_struct.to_string()
205/// }
206///
207/// pub struct B {
208/// map: String,
209/// map_field: String,
210/// map_struct: String,
211/// }
212///
213/// let a = A {
214/// map: 1,
215/// map_field: 2,
216/// map_struct: 3,
217/// };
218///
219/// let b: B = a.into();
220///
221/// assert_eq!(b.map, "1");
222/// assert_eq!(b.map_field, "2");
223/// assert_eq!(b.map_struct, "3");
224/// ```
225///
226#[proc_macro_derive(Convert, attributes(convert))]
227pub fn derive_convert(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
228 use_internal!(more_convert_derive_internal::derive_convert, input)
229}
230
231/// Automatically implements [`more_convert::EnumName`] on enum
232///
233/// # Where to use:
234/// - Only want the kind
235///
236/// # Note:
237/// - prefix and suffix are applied after rename_all
238///
239/// # EnumAttribute:
240/// - rename_all: apply rule to field name
241/// The possible values are ("lowercase", "UPPERCASE", "PascalCase", "camelCase",
242/// "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE")
243/// - prefix: add prefix to field name
244/// - suffix: add suffix to field name
245///
246/// # Variant Attribute:
247/// - rename: rename field, (prefix, suffix and rename_all are not applied)
248///
249/// # Examples
250///
251/// ## Normal
252///
253/// ```rust
254/// use more_convert::EnumName;
255///
256/// #[derive(EnumName)]
257/// pub enum Error {
258/// InvalidCode,
259/// ServerError,
260/// }
261///
262/// assert_eq!("InvalidCode", Error::InvalidCode.enum_name());
263/// assert_eq!("ServerError", Error::ServerError.enum_name());
264/// ```
265///
266/// ## rename and rename_all
267///
268/// ```rust
269/// use more_convert::EnumName;
270///
271/// #[derive(EnumName)]
272/// #[enum_name(rename_all = "snake_case")]
273/// pub enum Error {
274/// InvalidCode,
275/// ServerError,
276/// #[enum_name(rename = "NotFound")]
277/// NotFoundError,
278/// }
279///
280/// assert_eq!("invalid_code", Error::InvalidCode.enum_name());
281/// assert_eq!("server_error", Error::ServerError.enum_name());
282/// assert_eq!("NotFound", Error::NotFoundError.enum_name());
283/// ```
284///
285/// ## prefix and suffix
286/// ```rust
287/// use more_convert::EnumName;
288///
289/// #[derive(EnumName)]
290/// #[enum_name(prefix = "Error", suffix = "What")]
291/// pub enum Error {
292/// InvalidCode,
293/// ServerError,
294/// }
295///
296/// assert_eq!("ErrorInvalidCodeWhat", Error::InvalidCode.enum_name());
297/// assert_eq!("ErrorServerErrorWhat", Error::ServerError.enum_name());
298///
299#[proc_macro_derive(EnumName, attributes(enum_name))]
300pub fn derive_enum_name(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
301 use_internal!(more_convert_derive_internal::derive_enum_name, input)
302}