id_derive/
lib.rs

1//! The goal of this crate is to provide an easy newtype implementation for different types of
2//! strongly-typed identifiers.
3//!
4//! # Motivation
5//!
6//! Very often, I find myself utilizing many integer-based IDs. In effort to make it strongly
7//! typed, one typically uses a "newtype" pattern.
8//!
9//! ```
10//! struct MyId(usize);
11//!
12//! let id = MyId(1);
13//! assert_eq!(id.0, 1);
14//! assert_eq!(MyId(id.0 + 10).0, MyId(11).0);
15//! ```
16//!
17//! Notice how you have to access the tuple element with `.0` any time you want to perform any type
18//! of operations on the actual integer. One could approach this by implementing `Deref` trait but
19//! this is strongly discouraged; see: [Rust Docs](https://doc.rust-lang.org/std/ops/trait.Deref.html),
20//! [API Guidelines](https://rust-lang.github.io/api-guidelines/predictability.html#only-smart-pointers-implement-deref-and-derefmut-c-deref).
21//!
22//! This crate introduces a set of macros implementing certain operations on an ID.
23//!
24//! # Examples
25//!
26//! In the simplest case, you only need to a single derive [`Id`](derive.Id.html).
27//!
28//! ```
29//! # use id_derive::Id;
30//! #[derive(Id, Debug, PartialEq, Copy, Clone)]
31//! struct MyId(usize);
32//! // Construct from the inner type.
33//! let mut id = MyId::from(1);
34//! // Construct inner type from `MyId`.
35//! assert_eq!(usize::from(id), 1);
36//! // Display.
37//! assert_eq!(&id.to_string(), "1");
38//! // Add two IDs or inner to ID.
39//! assert_eq!(id + MyId(1), MyId(2));
40//! assert_eq!(id + 1, MyId(2));
41//! id += 1;
42//! id += MyId(1);
43//! assert_eq!(id, MyId(3));
44//! // Subtract
45//! assert_eq!(id - MyId(1), MyId(2));
46//! assert_eq!(id - 1, MyId(2));
47//! id -= 1;
48//! id -= MyId(1);
49//! assert_eq!(id, MyId(1));
50//! // Multiply
51//! assert_eq!(id * MyId(2), MyId(2));
52//! assert_eq!(id * 2, MyId(2));
53//! id *= 2;
54//! id *= MyId(2);
55//! assert_eq!(id, MyId(4));
56//! // Divide
57//! assert_eq!(id / MyId(2), MyId(2));
58//! assert_eq!(id / 2, MyId(2));
59//! id /= 2;
60//! id /= MyId(2);
61//! assert_eq!(id, MyId(1));
62//!
63//! ```
64//!
65//! Alternatively, you may devine only a subset of [available derives](#derives):
66//!
67//! ```
68//! # use id_derive::*;
69//! #[derive(Display, FromInner, IntoInner, Add, AddInner)]
70//! struct MyId(usize);
71//! ```
72
73#![warn(
74    missing_docs,
75    trivial_casts,
76    trivial_numeric_casts,
77    unused_import_braces,
78    unused_qualifications
79)]
80#![warn(clippy::all, clippy::pedantic)]
81#![allow(clippy::module_name_repetitions, clippy::default_trait_access)]
82#![doc(html_root_url = "https://docs.rs/id-derive/0.1.0")]
83
84extern crate proc_macro;
85
86use syn::{parse_macro_input, DeriveInput};
87
88mod operation;
89
90macro_rules! handle {
91    ($s:expr) => {
92        proc_macro::TokenStream::from(match $s {
93            Ok(tokens) => tokens,
94            Err(err) => return ::proc_macro::TokenStream::from(err.to_compile_error()),
95        })
96    };
97    ($($s:expr),*) => {{
98        let mut tokens = ::proc_macro2::TokenStream::new();
99        $(
100            match $s {
101                Ok(t) => {
102                    tokens.extend(t);
103                },
104                Err(err) => {
105                    return ::proc_macro::TokenStream::from(err.to_compile_error())
106                },
107            }
108        )*
109        return proc_macro::TokenStream::from(tokens);
110    }};
111}
112
113/// Implements `Display`.
114#[proc_macro_derive(Display)]
115pub fn display(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
116    let input = parse_macro_input!(item as DeriveInput);
117    handle!(operation::display("Display", &input))
118}
119
120/// Implements `Add<Self>`.
121#[proc_macro_derive(Add)]
122pub fn add_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
123    let input = parse_macro_input!(item as DeriveInput);
124    handle!(operation::add_self("Add", &input))
125}
126
127/// Implements `Add<T>` where `T` is the type of identifier.
128#[proc_macro_derive(AddInner)]
129pub fn add_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
130    let input = parse_macro_input!(item as DeriveInput);
131    handle!(operation::add_inner("AddInner", &input))
132}
133
134/// Implements `AddAssign<Self>`.
135#[proc_macro_derive(AddAssign)]
136pub fn add_assign_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
137    let input = parse_macro_input!(item as DeriveInput);
138    handle!(operation::add_assign_self("Add", &input))
139}
140
141/// Implements `AddAssign<T>` where `T` is the type of identifier.
142#[proc_macro_derive(AddAssignInner)]
143pub fn add_assign_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
144    let input = parse_macro_input!(item as DeriveInput);
145    handle!(operation::add_assign_inner("AddInner", &input))
146}
147
148/// Implements `Sub<Self>`.
149#[proc_macro_derive(Sub)]
150pub fn sub_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
151    let input = parse_macro_input!(item as DeriveInput);
152    handle!(operation::sub_self("Sub", &input))
153}
154
155/// Implements `Sub<T>` where `T` is the type of identifier.
156#[proc_macro_derive(SubInner)]
157pub fn sub_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
158    let input = parse_macro_input!(item as DeriveInput);
159    handle!(operation::sub_inner("SubInner", &input))
160}
161
162/// Implements `SubAssign<Self>`.
163#[proc_macro_derive(SubAssign)]
164pub fn sub_assign_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
165    let input = parse_macro_input!(item as DeriveInput);
166    handle!(operation::sub_assign_self("Sub", &input))
167}
168
169/// Implements `SubAssign<T>` where `T` is the type of identifier.
170#[proc_macro_derive(SubAssignInner)]
171pub fn sub_assign_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
172    let input = parse_macro_input!(item as DeriveInput);
173    handle!(operation::sub_assign_inner("SubInner", &input))
174}
175
176/// Implements `Mul<Self>`.
177#[proc_macro_derive(Mul)]
178pub fn mul_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
179    let input = parse_macro_input!(item as DeriveInput);
180    handle!(operation::mul_self("Mul", &input))
181}
182
183/// Implements `Mul<T>` where `T` is the type of identifier.
184#[proc_macro_derive(MulInner)]
185pub fn mul_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
186    let input = parse_macro_input!(item as DeriveInput);
187    handle!(operation::mul_inner("MulInner", &input))
188}
189
190/// Implements `MulAssign<Self>`.
191#[proc_macro_derive(MulAssign)]
192pub fn mul_assign_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
193    let input = parse_macro_input!(item as DeriveInput);
194    handle!(operation::mul_assign_self("MulAssign", &input))
195}
196
197/// Implements `MulAssign<T>` where `T` is the type of identifier.
198#[proc_macro_derive(MulAssignInner)]
199pub fn mul_assign_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
200    let input = parse_macro_input!(item as DeriveInput);
201    handle!(operation::mul_assign_inner("MulAssignInner", &input))
202}
203
204/// Implements `Div<Self>`.
205#[proc_macro_derive(Div)]
206pub fn div_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
207    let input = parse_macro_input!(item as DeriveInput);
208    handle!(operation::div_self("Div", &input))
209}
210
211/// Implements `Div<T>` where `T` is the type of identifier.
212#[proc_macro_derive(DivInner)]
213pub fn div_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
214    let input = parse_macro_input!(item as DeriveInput);
215    handle!(operation::div_inner("DivInner", &input))
216}
217
218/// Implements `DivAssign<Self>`.
219#[proc_macro_derive(DivAssign)]
220pub fn div_assign_self(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
221    let input = parse_macro_input!(item as DeriveInput);
222    handle!(operation::div_assign_self("DivAssign", &input))
223}
224
225/// Implements `DivAssign<T>` where `T` is the type of identifier.
226#[proc_macro_derive(DivAssignInner)]
227pub fn div_assign_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
228    let input = parse_macro_input!(item as DeriveInput);
229    handle!(operation::div_assign_inner("DivAssignInner", &input))
230}
231
232/// Implements `From<T>` where `T` is the type of identifier.
233#[proc_macro_derive(FromInner)]
234pub fn from_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
235    let input = parse_macro_input!(item as DeriveInput);
236    handle!(operation::from_inner("FromInner", &input))
237}
238
239/// Implements `From<Self>` for `T` where `T` is the type of identifier.
240#[proc_macro_derive(IntoInner)]
241pub fn into_inner(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
242    let input = parse_macro_input!(item as DeriveInput);
243    handle!(operation::into_inner("IntoInner", &input))
244}
245
246/// Equivalent to `derive(IntoInner, FromInner)`.
247#[proc_macro_derive(Convert)]
248pub fn convert(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
249    let input = parse_macro_input!(item as DeriveInput);
250    let from = operation::from_inner("Convert", &input);
251    let into = operation::into_inner("Convert", &input);
252    handle!(from, into)
253}
254
255/// Implement all available traits.
256#[proc_macro_derive(Id)]
257pub fn id(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
258    let input = parse_macro_input!(item as DeriveInput);
259    let derive_name = "Id";
260    handle!(
261        operation::from_inner(derive_name, &input),
262        operation::into_inner(derive_name, &input),
263        operation::add_self(derive_name, &input),
264        operation::add_inner(derive_name, &input),
265        operation::add_assign_self(derive_name, &input),
266        operation::add_assign_inner(derive_name, &input),
267        operation::sub_self(derive_name, &input),
268        operation::sub_inner(derive_name, &input),
269        operation::sub_assign_self(derive_name, &input),
270        operation::sub_assign_inner(derive_name, &input),
271        operation::mul_self(derive_name, &input),
272        operation::mul_inner(derive_name, &input),
273        operation::mul_assign_self(derive_name, &input),
274        operation::mul_assign_inner(derive_name, &input),
275        operation::div_self(derive_name, &input),
276        operation::div_inner(derive_name, &input),
277        operation::div_assign_self(derive_name, &input),
278        operation::div_assign_inner(derive_name, &input),
279        operation::display(derive_name, &input)
280    )
281}