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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/*! [![github]](https://github.com/sbailleul/mapper) [![crates-io]](https://crates.io/crates/mapper) [![docs-rs]](https://docs.rs/mapper) [![mapper-ci]](https://github.com/sbailleul/mapper/actions/workflows/rust.yml)

[github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
[crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
[docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
[mapper-ci]: https://github.com/sbailleul/mapper/actions/workflows/rust.yml/badge.svg
This library provides a convenient derive macro for implementing [mapper_api::Mapper<T>] or [std::convert::Into] trait and generate mapping without boilerplate.

<br>

# Example
```ignore
# use std::io;
use mapper::Mapper;

fn map_account_id(account_id: &u16) -> String{
    account_id.to_string()
}

#[derive(Mapper)]
#[to(Person)]
struct User{
    #[to(Person, field=_name)]
    pub name: String,
    #[to(Person, with=map_account_id)]
    pub account_id: u16,
    pub age: u8
}
struct Person{
    pub _name: String,
    pub account_id: String,
    pub age: u8
}
```

<br>

# Disclaimer
- Macro works only on structs
- Mapper doesn't handle nested properties


# Default behavior
Default behavior is to take each field of annotated struct and clone those fields in the destination struct initializer by implementing [mapper_api::Mapper<T>] trait :
```ignore
#[derive(Mapper)]
#[to(Person)]
struct User{
    pub name: String
}
struct Person{
    pub name: String
}
```
Generate 🔄 :
```ignore
impl Mapper<Person> for User{
    fn to(&self)->Person{
        Person{name: self.name.clone()}
    }
}
```
# Mapping types
Two mapping types are available :
- Automatic, generate mapping for destinations specified in [to struct attributes](#to-struct-attribute),
all fields of the source are used for mapping if they are not explicitly excluded.
You can't use automatic mapping if additive mapping is already used for destination and strategy
- Additive, generate mapping for destinations specified in [to field attributes](#to-field-attribute), only annotated fields are mapped.
You can't use additive mapping if automatic mapping is already used for destination and strategy

# Mapping strategies
Two mapping strategies are available :
- mapper(default), map source to destination without consuming source, generate implementation of [mapper_api::Mapper<T>]
- into, map source to destination by consuming source  of [std::convert::Into]

# To struct attribute
Generate automatic mapping for specified strategies.
- You can set multiple to attribute by struct
- Specify one or multiple destination types in this attribute : ```#[to(Animal, Vehicle)]```
- Specify one or multiple mapping strategies in this attribute : ```#[to(Animal, strategy=into, strategy=mapper)]```

# To field attribute
Complete automatic mapping configuration set on parent struct or provide additive mapping or exclude field from any mappings
- You can set multiple to attribute by field
- This attribute is forbidden if you use only DestinationType


## DestinationType
Type of the mapping destination. Mandatory argument unless field is unconditionally excluded.
### Generics
You can specify destination type with generics, these generics should be compatible with the fields of your src struct :
```ignore
#[derive(Mapper)]
#[to(Person::<String, u8>)]
struct User {
    name: String,
    age: u8
}
struct Person<T, U> {
    name: T,
    age: U
}
```

## Strategy
Trigger additive mapping for mapping destination and specified strategy e.g:

````ignore
#[derive(Mapper)]
struct User(#[to(Person, strategy=into)]u16, String);
struct Person(u16);
````
Generate 🔄 :

```ignore
impl Into<Person> for User{
    fn into(self)->Person{
        Person{0:self.0}
    }
}
```


## Exclude
Optional parameter, specify if the field is excluded for mapping, there is 2 kind of exclusion.
- Unconditionally exclusion, exclude field of any kind of mapping e.g :

````ignore
#[derive(Mapper)]
#[to(Person)]
struct User(u16, #[to(exclude)]String);
struct Person(u16);
````
Generate 🔄 :

```ignore
impl Mapper<Person> for User{
    fn into(self)->Person{
        Person{0:self.0}
    }
}
```

- Exclusion for specific destination (⚠️ not works for additive mapping), exclude field for specific destination mapping e.g :
````ignore
#[derive(Mapper)]
#[to(Person,Account, strategy=into)]
struct User(u16, #[to(Person,exclude)]String);
struct Account(u16, String);
struct Person(u16);
````
Generate 🔄 :

```ignore
impl Into<Person> for User{
    fn into(self)->Person{
        Person{0:self.0}
    }
}
impl Into<Account> for User{
    fn into(self)->Account{
        Account{0:self.0, 1: self.1}
    }
}
```


## Field
Optional parameter, target the destination type field e.g :
````ignore
#[derive(Mapper)]
#[to(Person)]
struct User{
    #[to(Person, field=0)
    name: String
};
struct Person( String);
````
Generate 🔄 :

```ignore
impl Mapper<Person> for User{
    fn to(&self)->Person{
        Person{0:self.name.clone()}
    }
}
```

## With
Optional parameter, provide a function to transform the annotated field to the destination field.
You can specify strategy used by with function as following : ```with(<strategy>)``` if you use with without specifying strategy : ```with``` mapper strategy will be used by default
Signature of the function should be in regards of used strategy  :
-  with(mapper) | with :
```ignore
fn foo_mapping(val: &<src_field_type>)-><dst_field_type>
```
- with(into) :
```ignore
fn foo_mapping(val: <src_field_type>)-><dst_field_type>
```

### Generics
You can use generics in your function if the generic types constraint respect the source field type and destination field type :
```ignore
    fn gen_func<T: Display>(val: &T)->String{
        val.to_string()
    }
    #[derive(Mapper)]
    #[to(Person)]
    struct User {
        #[to(Person, with=gen_func)]
        age: u16,
    }
    struct Person {
        age: String,
    }
```

*/

pub use mapper_api::*;
pub use mapper_impl::*;