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
//! Keeping your types under cover
//!
//!   - **Date:** July 17, 2017
//!   - **Subject:** Using type aliases and creating custom type wrappers for
//!     more expressive and safer code.
//!   - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e021.mp3
//!
//! <audio style="width: 100%" title="e021: Keeping your types under cover" controls preload=metadata><source src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e021.mp3"></audio>
//!
//!
//! Links and Notes
//! ---------------
//!
//! - [`Deref`]
//! - [`Iterator`]
//! - [`std::io::Result`]
//!
//! [`Deref`]: https://doc.rust-lang.org/stable/std/ops/trait.Deref.html
//! [`Iterator`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
//! [`std::io::Result`]: https://doc.rust-lang.org/stable/std/io/type.Result.html
//!
//!
//! Sponsors
//! --------
//!
//!   - [Anthony Deschamps]
//!   - Anthony Scotti
//!   - Aleksey Pirogov
//!   - Andreas Fischer
//!   - Andrew Thompson
//!   - Austin LeSure
//!   - [Behnam Esfahbod]
//!   - Benjamin Wasty
//!   - Brent Vatne
//!   - [Charlie Egan]
//!   - Chris Jones
//!   - [Chris Palmer]
//!   - Dan Abrams
//!   - [Daniel Collin]
//!   - [David W. Allen]
//!   - [Derek Morr]
//!   - Eugene Bulkin
//!   - [Henri Sivonen]
//!   - [Jakub "Limeth" Hlusička]
//!   - James Cooper
//!   - Jonathan Turner
//!   - Jordan Henderson
//!   - [Jupp Müller]
//!   - Justin Ossevoort
//!   - [Karl Hobley]
//!   - Keith Gray
//!   - Kilian Rault
//!   - Luca Schmid
//!   - Matt Rudder
//!   - Matthew Piziak
//!   - [Max Jacobson]
//!   - [Messense Lv]
//!   - Micael Bergeron
//!   - Ovidiu Curcan
//!   - [Pascal Hertleif]
//!   - [Patrick O'Doherty]
//!   - Peter Tillemans
//!   - Philipp Keller
//!   - Ralph Giles ("rillian")
//!   - Randy MacLeod
//!   - Raph Levien
//!   - reddraggone9
//!   - [Sebastián Ramírez Magrí]
//!   - Steven Murawski
//!   - [Stuart Hinson]
//!   - Tim Brooks
//!   - Tom Prince
//!   - Ty Overby
//!   - Tyler Harper
//!   - Vesa Kaihlavirta
//!   - Warren Harper
//!   - [William Roe]
//!   - Zaki
//!
//! [Anthony Deschamps]: https://github.com/adeschamps
//! [Behnam Esfahbod]: https://github.com/behnam
//! [Brent Vatne]: https://github.com/brentvatne
//! [Charlie Egan]: https://charlieegan3.com
//! [Chris Palmer]: http://red-oxide.org/
//! [Daniel Collin]: https://twitter.com/daniel_collin
//! [David W. Allen]: http://GitHub.com/DataRiot
//! [Derek Morr]: https://twitter.com/derekmorr
//! [Henri Sivonen]: https://hsivonen.fi/
//! [Jakub "Limeth" Hlusička]: https://github.com/Limeth
//! [Jupp Müller]: https://de.linkedin.com/in/juppm
//! [Karl Hobley]: https://github.com/kaedroho/
//! [Max Jacobson]: https://twitter.com/maxjacobson
//! [Messense Lv]: https://github.com/messense
//! [Pascal Hertleif]: https://pascalhertleif.de/
//! [Patrick O'Doherty]: https://twitter.com/patrickod
//! [Philipp Keller]: https://twitter.com/hansapla
//! [Sebastián Ramírez Magrí]: https://www.twitter.com/sebasmagri
//! [Stuart Hinson]: http://stuarth.github.io/
//! [William Roe]: http://willroe.me
//!
//! (Thanks to the couple people donating who opted out of the reward tier, as
//! well. You know who you are!)
//!
//! ### Become a sponsor
//!
//!   - <a href="https://www.patreon.com/newrustacean" rel="payment">Patreon</a>
//!   - [Venmo](https://venmo.com/chriskrycho)
//!   - [Dwolla](https://www.dwolla.com/hub/chriskrycho)
//!   - [Cash.me](https://cash.me/$chriskrycho)
//!   - [Flattr](https://flattr.com/profile/chriskrycho)
//!   - [PayPal.me](https://paypal.me/chriskrycho)
//!
//!
//! Contact
//! -------
//!
//!   - New Rustacean:
//!     + Twitter: [@newrustacean](https://www.twitter.com/newrustacean)
//!     + Email: [hello@newrustacean.com](mailto:hello@newrustacean.com)
//!   - Chris Krycho
//!     + GitHub: [chriskrycho](https://github.com/chriskrycho)
//!     + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)

use std::ops::Deref;

/// A type alias for a string that is appropriate to use as an email address.
pub type Email = String;

/// A "newtype" built by wrapping a `String` in a tuple struct.
///
/// Declare it and destructure it:
///
/// ```
/// # use show_notes::e021::*;
/// let email = EmailStruct("hello@newrustacean.com".into());
/// let EmailStruct(the_underlying_string) = email;
/// send(the_underlying_string);
/// ```
///
/// Note that we can implement `map` on it:
///
/// ```
/// # use show_notes::e021::*;
/// let email = EmailStruct("hello@newrustacean.com".into());
/// let transformed = email.map(|value| value.replace("newrustacean", "massaffection"));
/// println!("contact email for my other show is {:?}", transformed);
/// ```
///
/// And we can implement a (very badly behaving) `Iterator` on it, too. (And
/// I do mean *badly* behaved: do *not* attempted to use this iterator without
/// setting a limit on it, as it is infinite.)
///
/// ```
/// # use show_notes::e021::*;
/// let mut email = EmailStruct("hello@newrustacean.com".into());
/// let next = email.next();
/// let and_the_next = email.next();
/// assert_eq!(next, and_the_next, "It always returns the same thing 😱");
/// ```
///
/// (If we wanted to implement a better-behaved iterator, we'd need to do
/// substantially more work; for a good example of that on a wrapper type like
/// this, see [Result] or [Option].)
///
/// [Result]: https://doc.rust-lang.org/stable/std/result/enum.Result.html
/// [Option]: https://doc.rust-lang.org/stable/std/option/enum.Option.html
#[derive(Debug, PartialEq, Eq)]
pub struct EmailStruct(pub String);

impl EmailStruct {
    pub fn map<F: FnOnce(String) -> String>(self, f: F) -> EmailStruct {
        let EmailStruct(the_string) = self;
        EmailStruct(f(the_string))
    }
}

impl Iterator for EmailStruct {
    type Item = EmailStruct;

    fn next(&mut self) -> Option<EmailStruct> {
        let &mut EmailStruct(ref the_address) = self;
        Some(EmailStruct(the_address.clone()))
    }
}

impl Deref for EmailStruct {
    type Target = String;

    fn deref(&self) -> &String {
        // Return a reference to the underlying `String`, which itself
        // implements `Deref` for `&str`. That plus the `AsRef` impls
        // for each of those layers means you'll be able to write
        // `&EmailStruct` and simply pass it in to things expecting
        // `&str`.
        &self.0
    }
}

/// A "newtype" built by wrapping a `String` in a single-variant enum.
///
/// It's simple to use to create a wrapped variant, and then because it is
/// a single-variant enum, we can also destructure it:
///
/// ```
/// # use show_notes::e021::*;
/// let email = EmailEnum::Address("hello@newrustacean.com".into());
/// let EmailEnum::Address(just_the_string) = email;
/// send(just_the_string);
/// ```
///
/// Note, however, that it is *much* more verbose.
pub enum EmailEnum {
    Address(String),
}

impl Deref for EmailEnum {
    type Target = String;

    fn deref(&self) -> &String {
        match *self {
            EmailEnum::Address(ref string) => string,
        }
    }
}

/// A simple thing to demonstrate destructuring
///
/// ```
/// # use show_notes::e021::*;
/// let thing = ThingToDestructure {
///     a_field: "Neat!".into(),
///     another: 42,
/// };
///
/// let ThingToDestructure { a_field, another: can_rename } = thing;
/// println!("`a_field` is {} and another (`can_rename`) is {}", a_field, can_rename);
/// ```
pub struct ThingToDestructure {
    /// Just a field we can destructure.
    pub a_field: String,
    /// And another field we can destructure.
    pub another: i32,
}

/// A simple function showing you can use a `String` where an `Email` is required.
///
/// ```
/// # use show_notes::e021::*;
/// send(String::from("hello@newrustacean.com"));
/// ```
pub fn send(_to_address: Email) {}

/// A function which takes a string, to use with `Deref` and `EmailStruct`.
///
/// E.g. you can do this:
///
/// ```
/// # use show_notes::e021::*;
/// let email_struct = EmailStruct("hello@newrustacean.com".into());
/// takes_a_str(&email_struct);
/// ```
///
/// And likewise, with the enum variant:
///
/// ```
/// # use show_notes::e021::*;
/// let email_enum = EmailEnum::Address("hello@newrustacean.com".into());
/// takes_a_str(&email_enum)
/// ```
///
/// Note, however, that the `Deref` implementation is *much* more complicated
/// for the enum variant, as everything is in general.
pub fn takes_a_str(_some_str: &str) {}