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
//! Not dumb pointers.
//!
//!   - **Date:** June 17, 2016
//!   - **Subject:** `Box`, `String`, `Vec`, `Rc`, and `Arc` have this in
//!     common: they're not dumb.
//!   - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e015.mp3
//!
//! <audio style="width: 100%" title="e014: Stringing things along" controls preload=metadata>
//!   <source src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e015.mp3">
//! </audio>
//!
//!
//! Notes
//! -----
//!
//! This episode, we take a close look at smart pointer types---from a few we've
//! already talked about, like `Box`, `Vec`, and `String`, to some new ones,
//! like `Rc` and `Arc`.
//!
//!   - What smart pointers are, and what makes them 'smart'.
//!   - Why we want or need smart pointers.
//!   - A bit about `Box`.
//!   - A lot more about `Rc` and `Arc`.
//!
//! ***Note:*** The examples below are in-progress: the `Rc` example is complete
//! but not fully documented, and there's no examples yet for `Arc`---but there
//! will be! I expect to finish them over the course of this weekend, but I
//! wanted to go ahead and get the episode out!
//!
//! ### Further reading
//!
//!   - _The Rust Programming Language_:
//!       + [The Stack and the Heap]
//!       + [Choosing Your Guarantees] -- see especially the sections on
//!         `Rc` and `Arc`.
//!   - Rust by Example: [17.1: Box, stack, and heap][rbe]
//!   - API docs:
//!       + [`std::boxed`]
//!       + [`std::rc`]
//!       + [`stc::sync::Arc`]
//!
//! Links
//! -----
//!
//!   - [RustConf]
//!   - [Rust Belt Rust Conference]
//!       + [sessions]
//!   - [Rusty Radio]
//!       + [feed]
//!   - [Rust Exercism track]
//!       + [All exercism language tracks]
//!   - [RFC 1636: Require documentation for all new features.][RFC1636] (Note:
//!     I misspoke on the episode and said this was at rust-lang.org; it's not!
//!     It's on GitHub, wtih the rest of the RFCs, of course.)
//!
//! [RustConf]: http://rustconf.com
//! [Rust Belt Rust Conference]: http://www.rust-belt-rust.com
//! [sessions]: http://www.rust-belt-rust.com/sessions/
//! [Rusty Radio]: https://soundcloud.com/posix4e/sets/rustyradio
//! [feed]: http://feeds.soundcloud.com/users/soundcloud:users:1287419/sounds.rss
//! [Rust Exercism track]: http://exercism.io/languages/rust
//! [All exercism language tracks]: http://exercism.io/languages
//! [RFC1636]: https://github.com/rust-lang/rfcs/pull/1636
//! [The Stack and the Heap]: https://doc.rust-lang.org/book/the-stack-and-the-heap.html
//! [Choosing Your Guarantees]: https://doc.rust-lang.org/book/choosing-your-guarantees.html
//! [rbe]: http://rustbyexample.com/std/box.html
//! [`std::boxed`]: https://doc.rust-lang.org/std/boxed/index.html
//! [`std::rc`]: https://doc.rust-lang.org/std/rc/index.html
//! [`stc::sync::Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
//!
//!
//! Sponsors
//! --------
//!
//!   - Aleksey Pirogov
//!   - [Chris Palmer]
//!   - [Daniel Collin]
//!   - [Derek Morr]
//!   - Doug Reeves
//!   - Hamza Sheikh
//!   - Lachlan Collins
//!   - Leif Arne Storset
//!   - Luca Schmid
//!   - Micael Bergeron
//!   - [Pascal Hertleif]
//!   - Ralph Giles ("rillian")
//!   - Ralph "FriarTech" Loizzo
//!   - Raph Levien
//!   - reddraggone9
//!   - Ryan Ollos
//!   - Vesa Kaihlavirta
//!   - [William Roe]
//!
//! [Chris Palmer]: http://red-oxide.org/
//! [Daniel Collin]: twitter.com/daniel_collin
//! [Derek Morr]: https://twitter.com/derekmorr
//! [Pascal Hertleif]: https://pascalhertleif.de/
//! [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: [[email protected]](mailto:[email protected]ewrustacean.com)
//!   - Chris Krycho
//!     + GitHub: [chriskrycho](https://github.com/chriskrycho)
//!     + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)
//!
//!
//! Examples
//! --------
//!
//! The most basic examples of smart pointers involve the `Box` type, which
//! we've talked about before. Assume we had a type `Foo` which took a string in
//! its constructor, and that we wanted to box it up. We would just write:
//!
//! ```rust,ignore
//! let someFoo = Box::new(Foo::new("bar"));
//! ```
//!
//! It's also worth comparing the Rust code above with similar code in C++.
//! Assume we have a `class` with the same name; using a smart pointer (in this
//! case, `unique_ptr`, returned from `make_unique`) would give us this code:
//!
//! ```cpp
//! const auto someFoo = std::make_unique<const Foo>("bar");
//! ```
//!
//! Both examples declare a smart pointer named `someFoo` that points to an
//! immutable/constant `Foo` and where the pointer itself is immutable/constant.
//! However, note that the Rust code is briefer and (at least in my opinion)
//! substantially clearer than the corresponding C++ code to express the same
//! semantic content.
//!
//! I'm not including further comments on `Box` here in the docs, because we've
//! covered it before and it's fairly straightforward. The rest of these
//! materials focus entirely on `Rc` and `Arc`, as those are the most
//! interesting bits from today's episode.

use std::rc::{Rc, Weak};
// use std::sync::Arc;  // TODO

/// A trivial (and frankly rather silly) example for use with `Rc`.
pub struct FileData {
    contents: String,
}

impl FileData {
    pub fn new(contents: &str) -> FileData {
        FileData {
            contents: contents.to_string(),
        }
    }
}

pub struct ASendableType {}

/// Note that this function is *generic*: it will work for any type.
pub fn print_rc_count<T>(t: &Rc<T>) {
    println!("Reference count: {:}", Rc::strong_count(&t));
}

/// Note that this function is not generic because it assumes `FileData`.
fn print_rc_body(fd: &Rc<FileData>) {
    println!("The contents are: {:}", fd.contents);
}

/// Demonstrate the basics of reference-counted types. (Read the source, Luke!)
pub fn demonstrate_rc() {
    // Note that we have valid data here.
    let a_ref = get_wrapped_file_data();
    print_rc_body(&a_ref);
    print_rc_count(&a_ref); // Just 1
    let added_another_ref = a_ref.clone();
    print_rc_count(&a_ref); // 2

    // Create a block to show that we can get another copy.
    {
        let yet_another_ref = a_ref.clone();
        print_rc_count(&yet_another_ref); // 3
        print_rc_body(&yet_another_ref); // we can print the contents here.
    } // we've gone out of scope; `yet_another_ref` is deallocated here.

    print_rc_count(&a_ref); // 2 again
    drop(a_ref); // Remember, it doesn't matter which we drop!
    print_rc_count(&added_another_ref); // 1
    print_rc_body(&added_another_ref); // valid

    // Most explicit form:
    let a_weak_ref: Weak<FileData> = Rc::downgrade(&added_another_ref);
    // clone the weak ref.
    let _another_weak_ref = a_weak_ref.clone();
    print_rc_count(&added_another_ref); // still 1.

    // Now we *move* the reference into the other function.
    let empty_weak = get_empty_weak(added_another_ref);

    match empty_weak.upgrade() {
        Some(fd) => println!("{:}", fd.contents),
        None => println!("Nothing to see here. We're done."),
    }
}

/// Note that this takes ownership of the data.
pub fn get_empty_weak(fd: Rc<FileData>) -> Weak<FileData> {
    Rc::downgrade(&fd)
}

pub fn get_wrapped_file_data() -> Rc<FileData> {
    let plain_data = FileData::new("This would really read from a file. And not be terrible.");
    // Both of these now have "strong" references to the type. Neither "trumps"
    // the other; whichever goes out of scope first will be deallocated, but
    // *without* affecting the other.
    let wrapped = Rc::new(plain_data);
    print_rc_count(&wrapped);
    let a_reference_to_it = wrapped.clone();
    print_rc_count(&a_reference_to_it);

    a_reference_to_it
}