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