1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
mod input;
mod model_mapper;

use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;

/// Derives [From] and/or [TryFrom] another type to this one, or vice versa.
///
/// A `mapper` attribute is required at type-level and it's optional at field or variant level.
///
/// Attributes can be set directly if only one type is involved in the conversion:
/// ``` ignore
/// #[mapper(from, into, ty = OtherType, ignore(field = field_1), ignore(field = field_2))]
/// ```
/// Or they can be wrapped in a `derive` attribute to allow for multiple types:
/// ``` ignore
/// #[mapper(derive(try_from, ty = OtherType, ignore(field = field_1)))]
/// #[mapper(derive(into, ty = YetAnotherType))]
/// ```
///
/// If multiple types are involved, both variant and field level attributes can also be wrapped in a `when` attribute
/// and must set the `ty` they refer to:
/// ``` ignore
/// #[mapper(when(ty = OtherType, try_with = TryIntoMapper::try_map_removing_option))]
/// #[mapper(when(ty = YetAnotherType, skip))]
/// ```
///
/// The following attributes are available:
///
/// #### Type level attributes
/// - `ty = String` _(**mandatory**)_: The other type to derive the conversion
/// - `ignore_extra` _(optional)_: Wether to ignore all extra fields (for structs) or variants (for enums) of the other
///   type \*
/// - `ignore` _(optional, multiple)_: Additional fields (for structs with named fields) or variants (for enums) the
///   other type has and this one doesn't \*
///   - `field = String` _(mandatory)_: The field or variant to ignore
///   - `default = Expr` _(optional)_: The default value (defaults to `Default::default()`)
/// - `from` _(optional)_: Wether to derive [From] the other type for self
/// - `into` _(optional)_: Wether to derive [From] self for the other type
/// - `try_from` _(optional)_: Wether to derive [TryFrom] the other type for self
/// - `try_into` _(optional)_: Wether to derive [TryFrom] self for the other type
///
/// #### Variant level attributes
/// - `ignore_extra` _(optional)_: Wether to ignore all extra fields of the other variant (only valid for _from_ and
///   _try_from_) \*
/// - `ignore` _(optional, multiple)_: Additional fields of the variant that the other type variant has and this one
///   doesn't \*
///   - `field = String` _(mandatory)_: The field or variant to ignore
///   - `default = Expr` _(optional)_: The default value (defaults to `Default::default()`)
/// - `skip` _(optional)_: Wether to skip this variant because the other enum doesn't have it \*
/// - `default = Expr` _(optional)_: If skipped, the default value to populate this variant  (defaults to
///   `Default::default()`)
/// - `rename = "OtherVariant"` _(optional)_: To rename this variant on the other enum
///
/// #### Field level attributes
/// - `skip` _(optional)_: Wether to skip this field because the other type doesn't have it \*
/// - `default = Expr` _(optional)_: If skipped, the default value to populate this field  (defaults to
///   `Default::default()`)
/// - `rename = "other_field"` _(optional)_: To rename this field on the other type
/// - `with = mod::my_function` _(optional)_: If the field type doesn't implement [Into] the other, this property allows
///   you to customize the behavior by providing a conversion function
/// - `try_with = mod::my_function` _(optional)_: If the field type doesn't implement [TryInto] the other, this property
///   allows you to customize the behavior by providing a conversion function
///
/// **\*** When ignoring or skipping fields or variants it might be required that the enum or the field type implements
/// [Default] in order to properly populate it if no default is provided.
///
/// ## Examples
///
/// ```
/// # use model_mapper_macros::Mapper;
/// # #[derive(Default)]
/// # pub enum ResponseModel {
/// #     #[default]
/// #     Empty,
/// #     Text(String),
/// #     Data {
/// #         id: i64,
/// #         text: String,
/// #         status: Option<i32>,
/// #         internal: bool,
/// #     },
/// #     Unknown,
/// # }
/// # pub struct IntoMapper;
/// # impl IntoMapper {
/// #     pub fn map_wrapped<F,I>(opt: Option<F>) -> Option<I> { unreachable!() }
/// # }
/// # pub struct TryIntoMapper;
/// # impl TryIntoMapper {
/// #     pub fn try_map_wrapped<F,I>(opt: Option<F>) -> Result<Option<I>, std::io::Error> { unreachable!() }
/// # }
/// #[derive(Mapper)]
/// #[mapper(try_from, into, ty = ResponseModel, ignore(field = Unknown, default = CustomResponse::Empty))]
/// pub enum CustomResponse {
///     Empty,
///     #[mapper(rename = Text)]
///     Message(String),
///     #[mapper(ignore(field = internal))]
///     Data {
///         id: i64,
///         #[mapper(rename = "text")]
///         message: String,
///         #[mapper(with = IntoMapper::map_wrapped)]
///         #[mapper(try_with = TryIntoMapper::try_map_wrapped)]
///         status: Option<i16>,
///         #[mapper(skip)]
///         random: bool,
///     },
///     #[mapper(skip)]
///     Error,
/// }
/// ```
#[proc_macro_error]
#[proc_macro_derive(Mapper, attributes(mapper))]
pub fn model_mapper(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    model_mapper::r#impl(input).into()
}