qcell/
doctest_qcell.rs

1// Run ./update-compiletest-from-doctest.pl in crate base directory
2// after making any modification to compile_fail tests here.
3
4//! This tests the `QCell` implementation.
5//!
6//! It should be impossible to copy a QCellOwner:
7//!
8//! ```compile_fail
9//!# use qcell::{QCell, QCellOwner};
10//!# use std::rc::Rc;
11//! let mut owner1 = QCellOwner::new();
12//! let mut owner2 = owner1;
13//! let rc = Rc::new(QCell::new(&owner1, 100u32));  // Compile fail
14//! ```
15//!
16//! It should be impossible to clone a QCellOwner:
17//!
18//! ```compile_fail
19//!# use qcell::{QCell, QCellOwner};
20//!# use std::rc::Rc;
21//! let mut owner1 = QCellOwner::new();
22//! let owner2 = owner1.clone();  // Compile fail
23//! ```
24//!
25//! Two different owners can't borrow each other's cells immutably:
26//!
27//! ```should_panic
28//!# use qcell::{QCell, QCellOwner};
29//!# use std::rc::Rc;
30//! let mut owner1 = QCellOwner::new();
31//! let mut owner2 = QCellOwner::new();
32//! let c1 = Rc::new(QCell::new(&owner1, 100u32));
33//!
34//! let c1ref = owner2.ro(&c1);   // Panics here
35//! println!("{}", *c1ref);
36//! ```
37//!
38//! Or mutably:
39//!
40//! ```should_panic
41//!# use qcell::{QCell, QCellOwner};
42//!# use std::rc::Rc;
43//! let mut owner1 = QCellOwner::new();
44//! let mut owner2 = QCellOwner::new();
45//! let c1 = Rc::new(QCell::new(&owner1, 100u32));
46//!
47//! let c1mutref = owner2.rw(&c1);    // Panics here
48//! println!("{}", *c1mutref);
49//! ```
50//!
51//! You can't have two separate mutable borrows active on the same
52//! owner at the same time:
53//!
54//! ```compile_fail
55//!# use qcell::{QCell, QCellOwner};
56//!# use std::rc::Rc;
57//! let mut owner = QCellOwner::new();
58//! let c1 = Rc::new(QCell::new(&owner, 100u32));
59//! let c2 = Rc::new(QCell::new(&owner, 200u32));
60//!
61//! let c1mutref = owner.rw(&c1);
62//! let c2mutref=  owner.rw(&c2);  // Compile error
63//! *c1mutref += 1;
64//! *c2mutref += 2;
65//! ```
66//!
67//! However with `rw2()` you can do two mutable borrows at the
68//! same time, since this call checks at runtime that the two
69//! references don't refer to the same memory:
70//!
71//! ```
72//!# use qcell::{QCell, QCellOwner};
73//!# use std::rc::Rc;
74//!# let mut owner = QCellOwner::new();
75//!# let c1 = Rc::new(QCell::new(&owner, 100u32));
76//!# let c2 = Rc::new(QCell::new(&owner, 200u32));
77//! let (c1mutref, c2mutref) = owner.rw2(&c1, &c2);
78//! *c1mutref += 1;
79//! *c2mutref += 2;
80//! assert_eq!(303, owner.ro(&c1) + owner.ro(&c2));   // Success!
81//! ```
82//!
83//! You can't have a mutable borrow at the same time as an immutable
84//! borrow:
85//!
86//! ```compile_fail
87//!# use qcell::{QCell, QCellOwner};
88//!# use std::rc::Rc;
89//!# let mut owner = QCellOwner::new();
90//!# let c1 = Rc::new(QCell::new(&owner, 100u32));
91//!# let c2 = Rc::new(QCell::new(&owner, 200u32));
92//! let c1ref = owner.ro(&c1);
93//! let c1mutref = owner.rw(&c1);    // Compile error
94//! println!("{}", *c1ref);
95//! ```
96//!
97//! Not even if it's borrowing a different object:
98//!
99//! ```compile_fail
100//!# use qcell::{QCell, QCellOwner};
101//!# use std::rc::Rc;
102//!# let mut owner = QCellOwner::new();
103//!# let c1 = Rc::new(QCell::new(&owner, 100u32));
104//!# let c2 = Rc::new(QCell::new(&owner, 200u32));
105//! let c1mutref = owner.rw(&c1);
106//! let c2ref = owner.ro(&c2);    // Compile error
107//! *c1mutref += 1;
108//! ```
109//!
110//! Many immutable borrows at the same time is fine:
111//!
112//! ```
113//!# use qcell::{QCell, QCellOwner};
114//!# use std::rc::Rc;
115//!# let mut owner = QCellOwner::new();
116//!# let c1 = Rc::new(QCell::new(&owner, 100u32));
117//!# let c2 = Rc::new(QCell::new(&owner, 200u32));
118//! let c1ref = owner.ro(&c1);
119//! let c2ref = owner.ro(&c2);
120//! let c1ref2 = owner.ro(&c1);
121//! let c2ref2 = owner.ro(&c2);
122//! assert_eq!(600, *c1ref + *c2ref + *c1ref2 + *c2ref2);   // Success!
123//! ```
124//!
125//! Whilst a reference is active, it's impossible to drop the `Rc`:
126//!
127//! ```compile_fail
128//!# use qcell::{QCell, QCellOwner};
129//!# use std::rc::Rc;
130//!# let mut owner = QCellOwner::new();
131//!# let c1 = Rc::new(QCell::new(&owner, 100u32));
132//!# let c2 = Rc::new(QCell::new(&owner, 200u32));
133//! let c1ref = owner.ro(&c1);
134//! drop(c1);    // Compile error
135//! println!("{}", *c1ref);
136//! ```
137//!
138//! Also, whilst a reference is active, it's impossible to call
139//! anything else that uses the `owner` in an incompatible way,
140//! e.g. `&mut` when there's a `&` reference:
141//!
142//! ```compile_fail
143//!# use qcell::{QCell, QCellOwner};
144//!# use std::rc::Rc;
145//!# let mut owner = QCellOwner::new();
146//!# let c1 = Rc::new(QCell::new(&owner, 100u32));
147//!# let c2 = Rc::new(QCell::new(&owner, 200u32));
148//! fn test(o: &mut QCellOwner) {}
149//!
150//! let c1ref = owner.ro(&c1);
151//! test(&mut owner);    // Compile error
152//! println!("{}", *c1ref);
153//! ```
154//!
155//! Or `&` when there's a `&mut` reference:
156//!
157//! ```compile_fail
158//!# use qcell::{QCell, QCellOwner};
159//!# use std::rc::Rc;
160//!# let mut owner = QCellOwner::new();
161//!# let c1 = Rc::new(QCell::new(&owner, 100u32));
162//!# let c2 = Rc::new(QCell::new(&owner, 200u32));
163//! fn test(o: &QCellOwner) {}
164//!
165//! let c1mutref = owner.rw(&c1);
166//! test(&owner);    // Compile error
167//! *c1mutref += 1;
168//! ```
169//!
170//! `QCellOwner` and `QCell` should be both `Send` and `Sync` by default:
171//!
172//! ```
173//!# use qcell::{QCellOwner, QCell};
174//! fn is_send_sync<T: Send + Sync>() {}
175//! is_send_sync::<QCellOwner>();
176//! is_send_sync::<QCell<()>>();
177//! ```
178//!
179//! So for example we can share a cell ref between threads (Sync), and
180//! pass an owner back and forth (Send):
181//!
182//! ```
183//!# use qcell::{QCellOwner, QCell};
184//! let mut owner = QCellOwner::new();
185//! let cell = QCell::new(&owner, 100_i32);
186//!
187//! *owner.rw(&cell) += 1;
188//! let cell_ref = &cell;
189//! let mut owner = crossbeam::scope(move |s| {
190//!     s.spawn(move |_| {
191//!         *owner.rw(cell_ref) += 2;
192//!         owner
193//!     }).join().unwrap()
194//! }).unwrap();
195//! *owner.rw(&cell) += 4;
196//! assert_eq!(*owner.ro(&cell), 107);
197//! ```
198//!
199//! However you can't send a cell that's still borrowed:
200//!
201//! ```compile_fail
202//!# use qcell::{QCellOwner, QCell};
203//! let owner = QCellOwner::new();
204//! let cell = QCell::new(&owner, 100);
205//! let val_ref = owner.ro(&cell);
206//! std::thread::spawn(move || {
207//!     assert_eq!(*owner.ro(&cell), 100);
208//! }).join();
209//! assert_eq!(*val_ref, 100);
210//! ```
211//!
212//! If the contained type isn't `Sync`, though, then `QCell` shouldn't
213//! be `Sync` either:
214//!
215//! ```compile_fail
216//!# use qcell::QCell;
217//!# use std::cell::Cell;
218//! fn is_sync<T: Sync>() {}
219//! is_sync::<QCell<Cell<i32>>>();  // Compile fail
220//! ```
221//!
222//! ```compile_fail
223//!# use qcell::{QCell, QCellOwner};
224//!# use std::cell::Cell;
225//! let owner = QCellOwner::new();
226//! let cell = QCell::new(&owner, Cell::new(100));
227//!
228//! // This would be a data race if the compiler permitted it, but it doesn't
229//! std::thread::spawn(|| owner.ro(&cell).set(200));  // Compile fail
230//! owner.ro(&cell).set(300);
231//! ```
232//!
233//! If the contained type isn't `Send`, the `QCell` should be neither
234//! `Sync` nor `Send`:
235//!
236//! ```compile_fail
237//!# use qcell::QCell;
238//!# use std::rc::Rc;
239//! fn is_sync<T: Sync>() {}
240//! is_sync::<QCell<Rc<()>>>();  // Compile fail
241//! ```
242//!
243//! ```compile_fail
244//!# use qcell::QCell;
245//!# use std::rc::Rc;
246//! fn is_send<T: Send>() {}
247//! is_send::<QCell<Rc<()>>>();  // Compile fail
248//! ```
249//!
250//! ```compile_fail
251//!# use qcell::{QCell, QCellOwner};
252//!# use std::rc::Rc;
253//! let owner = QCellOwner::new();
254//! let cell = QCell::new(&owner, Rc::new(100));
255//!
256//! // We aren't permitted to move the Rc to another thread
257//! std::thread::spawn(move || {    // Compile fail
258//!     assert_eq!(100, **owner.ro(&cell));
259//! }).join();
260//! ```
261//!
262//! A reference obtained using `get_mut` should exclude any other kind
263//! of borrowing.
264//!
265//! ```compile_fail
266//!# use qcell::{QCell, QCellOwner};
267//! let owner = QCellOwner::new();
268//! let mut cell = QCell::new(&owner, 100);
269//! let cell_ref = cell.get_mut();
270//! assert_eq!(100, *owner.ro(&cell)); // Compile fail
271//! *cell_ref = 50;
272//! ```
273//!
274//! ```compile_fail
275//!# use qcell::{QCell, QCellOwner};
276//! let mut owner = QCellOwner::new();
277//! let mut cell = QCell::new(&owner, 100);
278//! let cell_ref = cell.get_mut();
279//! assert_eq!(100, *owner.rw(&cell)); // Compile fail
280//! *cell_ref = 50;
281//! ```
282//!
283//! ```compile_fail
284//!# use qcell::{QCell, QCellOwner};
285//! let owner = QCellOwner::new();
286//! let mut cell = QCell::new(&owner, 100);
287//! let cell_ref = owner.ro(&cell);
288//! *cell.get_mut() = 50; // Compile fail
289//! assert_eq!(100, *cell_ref);
290//! ```
291//!
292//! ```compile_fail
293//!# use qcell::{QCell, QCellOwner};
294//! let mut owner = QCellOwner::new();
295//! let mut cell = QCell::new(&owner, 100);
296//! let cell_ref = owner.rw(&cell);
297//! *cell.get_mut() = 50; // Compile fail
298//! assert_eq!(100, *cell_ref);
299//! ```
300//!
301//! `Default` is not implemented for `QCell`, since the owner must be
302//! provided explicity:
303//!
304//! ```compile_fail
305//!# use qcell::QCell;
306//! let mut cell: QCell<i32> = QCell::default();
307//! ```