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