o2o_macros/
lib.rs

1extern crate o2o_impl;
2
3use o2o_impl::expand::derive;
4use proc_macro::TokenStream;
5
6#[cfg(feature = "syn2")]
7use syn2 as syn;
8
9use syn::{parse_macro_input, DeriveInput};
10
11/// ### Object to Object mapper for Rust
12/// **o2o** can implement ...
13/// * `::core::convert::From<T>`
14/// * `::core::convert::TryFrom<T>`
15/// * `::core::convert::Into<T>`
16/// * `::core::convert::TryInto<T>`
17/// * `o2o::traits::IntoExisting<T>`
18/// * `o2o::traits::TryIntoExisting<T>`
19///  
20/// ... traits via procedural macro.
21///
22/// ### Basic example
23///
24/// ``` rust
25/// use o2o::o2o;
26///
27/// struct Person {
28///     id: u32,
29///     name: String,
30///     age: u8
31/// }
32///
33/// #[derive(o2o)]
34/// #[from_owned(Person)] // This tells o2o to generate 'From<Person> for PersonDto' implementation
35/// #[owned_try_into(Person, std::io::Error)] // This generates 'TryInto<Person> for PersonDto' with type Error = std::io::Error
36/// struct PersonDto {
37///     id: u32,
38///     name: String,
39///     age: u8
40/// }
41///
42/// // Applying #[derive(o2o)] on PersonDto allows you to do this:
43///
44/// let person = Person { id: 123, name: "John".into(), age: 42 };
45/// let dto = PersonDto::from(person);
46///
47/// assert_eq!(dto.id, 123); assert_eq!(dto.name, "John"); assert_eq!(dto.age, 42);
48///
49/// // and this:
50///
51/// let dto = PersonDto { id: 321, name: "Jack".into(), age: 23 };
52/// let person: Person = dto.try_into().unwrap();
53///
54/// assert_eq!(person.id, 321); assert_eq!(person.name, "Jack"); assert_eq!(person.age, 23);
55///
56/// // o2o also supports enums:
57///
58/// enum Creature {
59///     Person(Person),
60///     Cat { nickname: String },
61///     Dog(String),
62///     Other
63/// }
64///
65/// #[derive(o2o)]
66/// #[from_owned(Creature)]
67/// enum CreatureDto {
68///     Person(#[from(~.into())] PersonDto),
69///     Cat { nickname: String },
70///     Dog(String),
71///     Other
72/// }
73///
74/// let creature = Creature::Cat { nickname: "Floppa".into() };
75/// let dto: CreatureDto = creature.into();
76///
77/// if let CreatureDto::Cat { nickname } = dto { assert_eq!(nickname, "Floppa"); } else { assert!(false) }
78/// ```
79///
80/// ### For more examples, visit [github.com](https://github.com/Artem-Romanenia/o2o)
81#[proc_macro_derive(
82    o2o,
83    attributes(
84        owned_into,
85        ref_into,
86        into,
87        from_owned,
88        from_ref,
89        from,
90        map_owned,
91        map_ref,
92        map,
93        owned_try_into,
94        ref_try_into,
95        try_into,
96        owned_into_existing,
97        ref_into_existing,
98        into_existing,
99        try_from_owned,
100        try_from_ref,
101        try_from,
102        try_map_owned,
103        try_map_ref,
104        try_map,
105        owned_try_into_existing,
106        ref_try_into_existing,
107        try_into_existing,
108        child,
109        children,
110        child_parents,
111        parent,
112        ghost,
113        ghosts,
114        where_clause,
115        literal,
116        pattern,
117        type_hint,
118        o2o
119    )
120)]
121// TODO: Research, are there any downsides to having that many attributes?
122// (given that all but one are essentially shortcuts and can be avoided with alternative instr syntax)
123pub fn derive_o2o(input: TokenStream) -> TokenStream {
124    let input = parse_macro_input!(input as DeriveInput);
125    derive(&input).unwrap_or_else(|err| err.to_compile_error()).into()
126}