mongod_derive/
lib.rs

1//! # Mongo Derive
2//!
3//! This crate provides two derives `Bson` & `Mongo` for the [`mongo`][mongo] crate.
4//!
5//! ## Examples
6//!
7//! Deriving BSON
8//!
9//! ```
10//! # use mongod_derive::Bson;
11//! #[derive(Bson)]
12//! pub struct User {
13//!     name: String,
14//!     age: u32,
15//! }
16//! ```
17//!
18//! Deriving Mongo
19//!
20//! ```
21//! # mod wrap {
22//! # use mongod_derive::Mongo;
23//! # #[derive(mongod_derive::Bson)]
24//! #[derive(Mongo)]
25//! #[mongo(collection = "users", field, filter, update)]
26//! pub struct User {
27//!     name: String,
28//!     age: u32,
29//! }
30//! # }
31//! ```
32//!
33//! [mongo]: https://docs.rs/mongo
34#[macro_use]
35extern crate quote;
36#[macro_use]
37extern crate syn;
38
39use proc_macro::TokenStream;
40use syn::DeriveInput;
41
42mod ast;
43mod bson;
44mod mongo;
45
46/// Derives implementations for `TryFrom` so that the decorated type can be converted `to` & `from`
47/// BSON.
48///
49/// ## Container Attributes
50///
51/// - #[bson(from)]: derives `TryFrom` on `Bson` for `type`
52/// - #[bson(into)]: derives `TryFrom` on `type` for `Bson`
53///
54/// ### `#[bson(from)]`
55///
56/// Tells the derive to only implement the `from` parts of the derive, i.e. deserialising only.
57///
58/// ```
59/// # use mongod_derive::Bson;
60/// use std::convert::TryFrom;
61///
62/// #[derive(Debug, Bson)]
63/// #[bson(from)]
64/// struct User {
65///     name: String,
66/// }
67/// let mut doc = mongod::bson::Document::new();
68/// doc.insert("name", "foo".to_owned());
69/// let bson = mongod::bson::Bson::Document(doc);
70///
71/// let user = User::try_from(bson).unwrap();
72///
73/// println!("{:?}", user);
74/// ```
75///
76/// ### `#[bson(into)]`
77///
78/// Tells the derive to only implement the `into` parts of the derive, i.e. serialising only.
79///
80/// ```
81/// # use mongod_derive::Bson;
82/// use std::convert::TryFrom;
83///
84/// #[derive(Bson)]
85/// #[bson(into)]
86/// struct User {
87///     name: String,
88/// }
89///
90/// let user = User { name: "foo".to_owned() };
91///
92/// let bson = mongod::bson::Bson::try_from(user).unwrap();
93///
94/// println!("{:?}", bson);
95/// ```
96///
97/// ## Field Attributes
98///
99/// - #[bson(serde)]
100///
101/// ### `#[bson(serde)]`
102///
103/// Tells the derive to use `serde` for the decorated field.
104/// ```
105/// # use mongod_derive::Bson;
106/// use std::convert::TryFrom;
107///
108/// #[derive(Bson)]
109/// struct User {
110///     name: String,
111///     #[bson(serde)]
112///     age: u32,
113/// }
114///
115/// let user = User { name: "foo".to_owned(), age: 0 };
116///
117/// let bson = mongod::bson::Bson::try_from(user).unwrap();
118///
119/// println!("{:?}", bson);
120/// ```
121#[proc_macro_derive(Bson, attributes(bson))]
122pub fn derive_bson(input: TokenStream) -> TokenStream {
123    let input = parse_macro_input!(input as DeriveInput);
124    bson::expand_derive_bson(&input)
125        .unwrap_or_else(to_compile_errors)
126        .into()
127}
128
129/// Derives mongo traits on the decorated type.
130///
131/// ## Container Attributes
132///
133/// - `#[mongo(collection = "...")]`: derives the `Collection` trait
134/// - `#[mongo(field)]`: derives the `AsField` & `Field` traits
135/// - `#[mongo(filter)]`: derives the `AsFilter` & `Filter` traits
136/// - `#[mongo(oid)]`: derives the `_id` field for derived `Field` traits
137/// - `#[mongo(update)]`: derives the `AsUpdate` & `Update` traits
138///
139/// ### `#[mongo(collection = "...")]`
140///
141/// Tells the derive to implement the `Collection` trait where the `"..."` is the name of the
142/// collection.
143///
144/// ```
145/// # mod wrap {
146/// # use mongod_derive::Mongo;
147/// # #[derive(mongod_derive::Bson)]
148/// #[derive(Mongo)]
149/// #[mongo(collection = "users")]
150/// pub struct User {
151///     name: String,
152///     age: u32,
153/// }
154/// # }
155/// ```
156///
157/// ### `#[mongo(field)]`
158///
159/// Tells the derive to implement the `AsField` & `Field` traits.
160///
161/// ```
162/// # mod wrap {
163/// # use mongod_derive::Mongo;
164/// # #[derive(mongod_derive::Bson)]
165/// #[derive(Mongo)]
166/// #[mongo(field)]
167/// pub struct User {
168///     name: String,
169///     age: u32,
170/// }
171///
172/// // The derived field enum can be exposed from the derived module which uses the type's name in
173/// // snake_case
174/// use self::user::Field;
175/// # }
176/// ```
177///
178/// ### `#[mongo(filter)]`
179///
180/// Tells the derive to implement the `AsFilter` & `Filter` traits.
181///
182/// ```
183/// # mod wrap {
184/// # use mongod_derive::Mongo;
185/// # #[derive(mongod_derive::Bson)]
186/// #[derive(Mongo)]
187/// #[mongo(filter)]
188/// pub struct User {
189///     name: String,
190///     age: u32,
191/// }
192///
193/// // The derived filter struct can be exposed from the derived module which uses the type's name in
194/// // snake_case
195/// use self::user::Filter;
196/// # }
197/// ```
198///
199/// ### `#[mongo(oid)]`
200///
201/// Tells the derive to implement the `_id` field for derived `Filter` traits.
202///
203/// ```
204/// # mod wrap {
205/// # use mongod_derive::Mongo;
206/// # #[derive(mongod_derive::Bson)]
207/// #[derive(Mongo)]
208/// #[mongo(filter, oid)]
209/// pub struct User {
210///     name: String,
211///     age: u32,
212/// }
213///
214/// // The derived filter struct can be exposed from the derived module which uses the type's name in
215/// // snake_case
216/// use self::user::Filter;
217/// # }
218/// ```
219///
220/// ### `#[mongo(update)]`
221///
222/// Tells the derive to implement the `AsUpdate` & `Update` traits.
223///
224/// ```
225/// # mod wrap {
226/// # use mongod_derive::Mongo;
227/// # #[derive(mongod_derive::Bson)]
228/// #[derive(Mongo)]
229/// #[mongo(update)]
230/// pub struct User {
231///     name: String,
232///     age: u32,
233/// }
234///
235/// // The derived update struct can be exposed from the derived module which uses the type's name in
236/// // snake_case
237/// use self::user::Update;
238/// # }
239/// ```
240///
241/// ## Field Attributes
242///
243/// - `#[mongo(serde)]`: tells the derive that the field should be handled using serde
244/// - `#[mongo(skip)]`: tells the derive to skip the field for `field`, `filter` & `update`
245///
246/// ### `#[mongo(serde)]`
247///
248/// Tells the derive that the field should be handled using serde
249///
250/// ```
251/// # mod wrap {
252/// # use mongod_derive::Mongo;
253/// # #[derive(mongod_derive::Bson)]
254/// #[derive(Mongo)]
255/// #[mongo(collection = "users")]
256/// pub struct User {
257///     name: String,
258///     #[mongo(serde)]
259///     age: u32,
260/// }
261/// # }
262/// ```
263///
264/// ### `#[mongo(skip)]`
265///
266/// Tells the derive to skip the field for `field`, `filter` & `update`
267///
268/// ```
269/// # mod wrap {
270/// # use mongod_derive::Mongo;
271/// # #[derive(mongod_derive::Bson)]
272/// #[derive(Mongo)]
273/// #[mongo(collection = "users")]
274/// pub struct User {
275///     name: String,
276///     #[mongo(skip)]
277///     age: u32,
278/// }
279/// # }
280/// ```
281#[proc_macro_derive(Mongo, attributes(mongo))]
282pub fn derive_collection(input: TokenStream) -> TokenStream {
283    let input = parse_macro_input!(input as DeriveInput);
284    mongo::expand_derive_mongo(&input)
285        .unwrap_or_else(to_compile_errors)
286        .into()
287}
288
289fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
290    let compile_errors = errors.iter().map(syn::Error::to_compile_error);
291    quote!(#(#compile_errors)*)
292}