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}