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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
//! A library to generate "microtypes" (A.K.A. "newtypes"). Opinionated in favour of ergonomics
//! over maximum flexibility.
//!
//! A microtype is a thin wrapper around an underlying type, that helps disambiguate similar uses
//! of the same type
//!
//! For example, consider the following code from an imaginary e-commerce web backend:
//! ```
//! # #[macro_use]
//! # extern crate microtype;
//! # fn retrieve_user_id() -> String { "".into() }
//! # fn retrieve_order_id() -> String { "".into() }
//! fn handle_order(user_id: String, order_id: String) {
//! // ...
//! }
//!
//! fn main() {
//! let user_id = retrieve_user_id();
//! let order_id = retrieve_order_id();
//!
//! handle_order(order_id, user_id);
//! }
//! ```
//!
//! This code compiles, but has a bug: the `order_id` and `user_id` are used in the wrong order.
//! This example is fairly trivial and easy to spot, but the larger a project gets, the harder it
//! becomes to detect these issues. This becomes especially troublesome if you want to refactor. For
//! example, if you wanted to swap the order of the arguments, you'd have to make sure you visited
//! all the calls to this function and swapped the arguments manually. Luckily, we can get the
//! compiler to help with this.
//!
//! Microtypes solve this problem. They wrap some inner type, and allow the compiler to distinguish
//! between different uses of the same underlying type. For example, we could rewrite the earlier
//! example as:
//!
//! ```compile_fail
//! # #[macro_use]
//! # extern crate microtype;
//! # fn retrieve_user_id() -> String { "".into() }
//! # fn retrieve_order_id() -> String { "".into() }
//! // Generate wrappers around String called UserId and OrderId
//! microtype! {
//! String {
//! UserId,
//! OrderId,
//! }
//! }
//!
//! fn handle_order(user_id: UserId, order_id: OrderId) {
//! // ...
//! }
//!
//! fn main() {
//! let user_id: OrderId = retrieve_user_id();
//! let order_id: UserId = retrieve_order_id();
//!
//! handle_order(order_id, user_id); // Error: incompatible types
//! }
//! ```
//! Excellent, a run-time error has been turned into a compile time error.
//!
//! ## Basic usage
//!
//! To declare microtypes, use the ['microtype::microtype'] macro:
//! ```
//! # #[macro_use]
//! # extern crate microtype;
//! # use microtype::Microtype;
//! microtype! {
//! // these attributes apply to all microtypes defined in this block
//! #[derive(Debug, Clone)]
//! String {
//! #[derive(PartialEq)]
//! UserId, // implements Debug, Clone and PartialEq
//!
//! Username, // only implements Debug and Clone
//! }
//!
//! // multiple inner types can be used in a single macro
//! i64 {
//! Timestamp
//! }
//!
//! // use the `#[secret]` attribute to mark a type as "secret"
//! #[secret]
//! String {
//! Password
//! }
//!
//! // use `#[secret(serialize)]` to make a secret type implement serde::Serialize
//! String {
//! SessionToken
//! }
//! }
//!
//! fn main() {
//! let user_id = UserId::new("id".into()); // create new UserId
//! let string = user_id.into_inner(); // consume UserId, return inner String
//! let username = Username::new(string); // create new Username
//!
//! // sometimes you need to explicitly change the type of a value:
//! let user_id: UserId = username.convert();
//!
//! // microtypes also optionally implement Deref
//! let length = user_id.len();
//! assert_eq!(length, 2);
//! }
//! ```
//!
//!
//! ## Secrets
//!
//! Some types may be considered "sensitive" (for example: passwords, session tokens, etc).
//! For this purpose, microtypes can be marked as `#[secret]`:
//! ```
//! # use microtype::microtype;
//! # use microtype::SecretMicrotype;
//! # use microtype::secrecy::ExposeSecret;
//! microtype! {
//! #[secret]
//! String {
//! Password
//! }
//! }
//!
//! fn main() {
//! let password = Password::new("secret password".to_string());
//! assert_eq!(password.expose_secret(), "secret password");
//! }
//! ```
//! Secret microtypes don't implement [`Microtype`], instead they implement
//! [`SecretMicrotype`], which has a much more restrictive API:
//! - Mutable and owned access to the inner data is not possible, it is only possible to get a
//! shared reference to the inner data via [`secrecy::ExposeSecret::expose_secret`], which makes
//! accesses easier to audit.
//! - They `#[derive(Debug, Clone)]` (and optionally `Serialize` and `Deserialize`) but do not support adding extra derive macros.
//!
//! Internally, they wrap the contained data in [`secrecy::Secret`], which provides some nice
//! safety features. In particular:
//! - The debug representation is redacted. This is can prevent against accidentally leaking
//! data to logs, but it still *has* a `Debug` implementation (so you can still
//! `#[derive(Debug)]` on structs which contain secret data)
//! - Data is zeroized after use, meaning the underlying data is overwritten with 0s, which
//! ensures sensitive data exists in memory only for as long as is needed. (Caveat: not all types
//! have perfect zeroize implementations. Notably `Vec` (and `String`) will not be able to zeroize
//! previous allocations)
//! - when using `serde`, secret microtypes do not implement `Serialize`, to avoid accidentally
//! leaking secret data
//!
//! ## Serializable Secrets
//!
//! The fact that secret microtypes do not implement `Serialize` can be overly restrictive
//! sometimes. There are many types (e.g. session tokens) which are sensitive enough to warrant
//! redacting their debug implementation, but also need to be serialized. For types like this, you
//! can use `#[secret(serialize)]` to make the type implement `Serialize`.
//!
//! ```ignore
//! # use serde::Serialize;
//! # use microtype::microtype;
//! microtype! {
//! #[secret(serialize)]
//! String {
//! SessionToken
//! }
//! }
//!
//! #[derive(Serialize)]
//! struct LoginResponse {
//! token: SessionToken
//! }
//! ```
//!
//! ## Type Hints
//!
//! Proc-macros are run before type information is available, so can only use the text of the
//! invocation. Given that, a proc-macro can't distinguish between the `String` type provided by
//! the standard library and a custom `struct String;`. You can use a type hint to mark a microtype
//! as wrapping a well-known type, to generate more helpful implementations for you:
//!
//! - If the wrapped type is a `String`, you can use `#[string]` to provide a few extra
//! implementations (e.g. `FromStr`, `From<&str>`, `Display`)
//! - If the wrapped type is an integer type, you can use `#[int]` to provide other extra
//! implementations: various `fmt` traits (e.g. `UpperHex`, etc), as well as arithmetic traits
//! (`Add`, `AddAssign`, etc). These are incomplete, please open a PR/issue if there are implementations
//! you rely on that are missing
//!
//! For example:
//! ```
//! # use microtype::*;
//! microtype! {
//! #[string]
//! String {
//! Email
//! }
//!
//! #[int]
//! i32 {
//! Num
//! }
//! }
//!
//! fn main() {
//! let email = Email::from("email");
//! let num = Num::from(123);
//!
//! println!("{email}");
//! println!("display: {num}, hex: {num:x}");
//! }
//! ```
//!
//!
//! ## Feature flags
//!
//! The following feature flags are provided, to help customize the behaviour of the types creates:
//! - `serde` - when enabled, any type created will derive `Serialize` and `Deserialize`, and will
//! be `#[serde(transparent)]`
//! - `deref_impls` - some people argue that implementing `Deref` and `DerefMut` on a non-pointer container is
//! unidiomatic. Others prefer the ergonomics of being able to call associated functions more
//! easily. If `deref_impls` is enabled, microtypes will deref to their inner types
//! - `test_impls` - makes secret microtypes easier to work with in test environments by:
//! - making their `Debug` implmentation print their actual value instead of `"REDACTED"`
//! - making them derive `PartialEq`
//! - `secret` - enables secret microtypes, discussed below:
//! - `diesel` - if enabled, any attribtes of the form `#[diesel(sql_type = ...)]` will be
//! captured, and `FromSql` and `ToSql` implementations will be generated. Note, you will
//! generally also want to `#[derive(AsExpression, FromSqlRow)]`
/* TRAIT DEFS */
/// A trait implemented by microtypes
///
/// Provides some useful common functions for working with microtypes
/// A trait implemented by secret microtypes
///
/// Due to their nature, secret microtypes are more restrictive than regular microtypes:
/// - `inner`, `inner_mut` and `into_inner` are removed, since they can allow accidental use of
/// the contained secret.
/// - `SecretMicrotype` requires `ExposeSecret<Self::Inner>`; to use the contained data, use
/// `.expose_secret()`
///
/// The wrapped type must also implement [`secrecy::Zeroize`]
pub use microtype;
pub use secrecy;