blob: e753ea8f9197ed0f04e3d3b0d430946fbafd1348 [file] [log] [blame]
Chih-Hung Hsiehde83b092020-04-07 14:24:01 -07001// Original work Copyright (c) 2014 The Rust Project Developers
2// Modified work Copyright (c) 2016-2018 Nikita Pekin and the lazycell contributors
3// See the README.md file at the top-level directory of this distribution.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11#![cfg_attr(not(test), no_std)]
12
13#![deny(missing_docs)]
14#![cfg_attr(feature = "nightly", feature(plugin))]
15#![cfg_attr(feature = "clippy", plugin(clippy))]
16
17//! This crate provides a `LazyCell` struct which acts as a lazily filled
18//! `Cell`.
19//!
20//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of
21//! the entire object, but only of the borrows returned. A `LazyCell` is a
22//! variation on `RefCell` which allows borrows to be tied to the lifetime of
23//! the outer object.
24//!
25//! # Example
26//!
27//! The following example shows a quick example of the basic functionality of
28//! `LazyCell`.
29//!
30//! ```
31//! use lazycell::LazyCell;
32//!
33//! let lazycell = LazyCell::new();
34//!
35//! assert_eq!(lazycell.borrow(), None);
36//! assert!(!lazycell.filled());
37//! lazycell.fill(1).ok();
38//! assert!(lazycell.filled());
39//! assert_eq!(lazycell.borrow(), Some(&1));
40//! assert_eq!(lazycell.into_inner(), Some(1));
41//! ```
42//!
43//! `AtomicLazyCell` is a variant that uses an atomic variable to manage
44//! coordination in a thread-safe fashion. The limitation of an `AtomicLazyCell`
45//! is that after it is initialized, it can't be modified.
46
Matthew Maurerfea35c52020-07-06 13:19:26 -070047// ANDROID: Unconditionally use std to allow building as a dylib.
Chih-Hung Hsiehde83b092020-04-07 14:24:01 -070048#[macro_use]
Matthew Maurerfea35c52020-07-06 13:19:26 -070049extern crate std;
Chih-Hung Hsiehde83b092020-04-07 14:24:01 -070050
51use std::cell::UnsafeCell;
52use std::mem;
53use std::sync::atomic::{AtomicUsize, Ordering};
54
55/// A lazily filled `Cell`, with mutable contents.
56///
57/// A `LazyCell` is completely frozen once filled, **unless** you have `&mut`
58/// access to it, in which case `LazyCell::borrow_mut` may be used to mutate the
59/// contents.
60#[derive(Debug, Default)]
61pub struct LazyCell<T> {
62 inner: UnsafeCell<Option<T>>,
63}
64
65impl<T> LazyCell<T> {
66 /// Creates a new, empty, `LazyCell`.
67 pub fn new() -> LazyCell<T> {
68 LazyCell { inner: UnsafeCell::new(None) }
69 }
70
71 /// Put a value into this cell.
72 ///
73 /// This function will return `Err(value)` is the cell is already full.
74 pub fn fill(&self, value: T) -> Result<(), T> {
75 let slot = unsafe { &mut *self.inner.get() };
76 if slot.is_some() {
77 return Err(value);
78 }
79 *slot = Some(value);
80
81 Ok(())
82 }
83
84 /// Put a value into this cell.
85 ///
86 /// Note that this function is infallible but requires `&mut self`. By
87 /// requiring `&mut self` we're guaranteed that no active borrows to this
88 /// cell can exist so we can always fill in the value. This may not always
89 /// be usable, however, as `&mut self` may not be possible to borrow.
90 ///
91 /// # Return value
92 ///
93 /// This function returns the previous value, if any.
94 pub fn replace(&mut self, value: T) -> Option<T> {
95 mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
96 }
97
98 /// Test whether this cell has been previously filled.
99 pub fn filled(&self) -> bool {
100 self.borrow().is_some()
101 }
102
103 /// Borrows the contents of this lazy cell for the duration of the cell
104 /// itself.
105 ///
106 /// This function will return `Some` if the cell has been previously
107 /// initialized, and `None` if it has not yet been initialized.
108 pub fn borrow(&self) -> Option<&T> {
109 unsafe { &*self.inner.get() }.as_ref()
110 }
111
112 /// Borrows the contents of this lazy cell mutably for the duration of the cell
113 /// itself.
114 ///
115 /// This function will return `Some` if the cell has been previously
116 /// initialized, and `None` if it has not yet been initialized.
117 pub fn borrow_mut(&mut self) -> Option<&mut T> {
118 unsafe { &mut *self.inner.get() }.as_mut()
119 }
120
121 /// Borrows the contents of this lazy cell for the duration of the cell
122 /// itself.
123 ///
124 /// If the cell has not yet been filled, the cell is first filled using the
125 /// function provided.
126 ///
127 /// # Panics
128 ///
129 /// Panics if the cell becomes filled as a side effect of `f`.
130 pub fn borrow_with<F: FnOnce() -> T>(&self, f: F) -> &T {
131 if let Some(value) = self.borrow() {
132 return value;
133 }
134 let value = f();
135 if self.fill(value).is_err() {
136 panic!("borrow_with: cell was filled by closure")
137 }
138 self.borrow().unwrap()
139 }
140
141 /// Borrows the contents of this `LazyCell` mutably for the duration of the
142 /// cell itself.
143 ///
144 /// If the cell has not yet been filled, the cell is first filled using the
145 /// function provided.
146 ///
147 /// # Panics
148 ///
149 /// Panics if the cell becomes filled as a side effect of `f`.
150 pub fn borrow_mut_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
151 if !self.filled() {
152 let value = f();
153 if self.fill(value).is_err() {
154 panic!("borrow_mut_with: cell was filled by closure")
155 }
156 }
157
158 self.borrow_mut().unwrap()
159 }
160
161 /// Same as `borrow_with`, but allows the initializing function to fail.
162 ///
163 /// # Panics
164 ///
165 /// Panics if the cell becomes filled as a side effect of `f`.
166 pub fn try_borrow_with<E, F>(&self, f: F) -> Result<&T, E>
167 where F: FnOnce() -> Result<T, E>
168 {
169 if let Some(value) = self.borrow() {
170 return Ok(value);
171 }
172 let value = f()?;
173 if self.fill(value).is_err() {
174 panic!("try_borrow_with: cell was filled by closure")
175 }
176 Ok(self.borrow().unwrap())
177 }
178
179 /// Same as `borrow_mut_with`, but allows the initializing function to fail.
180 ///
181 /// # Panics
182 ///
183 /// Panics if the cell becomes filled as a side effect of `f`.
184 pub fn try_borrow_mut_with<E, F>(&mut self, f: F) -> Result<&mut T, E>
185 where F: FnOnce() -> Result<T, E>
186 {
187 if self.filled() {
188 return Ok(self.borrow_mut().unwrap());
189 }
190 let value = f()?;
191 if self.fill(value).is_err() {
192 panic!("try_borrow_mut_with: cell was filled by closure")
193 }
194 Ok(self.borrow_mut().unwrap())
195 }
196
197 /// Consumes this `LazyCell`, returning the underlying value.
198 pub fn into_inner(self) -> Option<T> {
199 // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
200 // function. This unsafe can be removed when supporting Rust older than
201 // 1.25 is not needed.
202 #[allow(unused_unsafe)]
203 unsafe { self.inner.into_inner() }
204 }
205}
206
207impl<T: Copy> LazyCell<T> {
208 /// Returns a copy of the contents of the lazy cell.
209 ///
210 /// This function will return `Some` if the cell has been previously initialized,
211 /// and `None` if it has not yet been initialized.
212 pub fn get(&self) -> Option<T> {
213 unsafe { *self.inner.get() }
214 }
215}
216
217impl <T: Clone> Clone for LazyCell<T> {
218 /// Create a clone of this `LazyCell`
219 ///
220 /// If self has not been initialized, returns an uninitialized `LazyCell`
221 /// otherwise returns a `LazyCell` already initialized with a clone of the
222 /// contents of self.
223 fn clone(&self) -> LazyCell<T> {
224 LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) }
225 }
226}
227
228// Tracks the AtomicLazyCell inner state
229const NONE: usize = 0;
230const LOCK: usize = 1;
231const SOME: usize = 2;
232
233/// A lazily filled and thread-safe `Cell`, with frozen contents.
234#[derive(Debug, Default)]
235pub struct AtomicLazyCell<T> {
236 inner: UnsafeCell<Option<T>>,
237 state: AtomicUsize,
238}
239
240impl<T> AtomicLazyCell<T> {
241 /// An empty `AtomicLazyCell`.
242 pub const NONE: Self = Self {
243 inner: UnsafeCell::new(None),
244 state: AtomicUsize::new(NONE),
245 };
246
247 /// Creates a new, empty, `AtomicLazyCell`.
248 pub fn new() -> AtomicLazyCell<T> {
249 Self::NONE
250 }
251
252 /// Put a value into this cell.
253 ///
254 /// This function will return `Err(value)` is the cell is already full.
255 pub fn fill(&self, t: T) -> Result<(), T> {
256 if NONE != self.state.compare_and_swap(NONE, LOCK, Ordering::Acquire) {
257 return Err(t);
258 }
259
260 unsafe { *self.inner.get() = Some(t) };
261
262 if LOCK != self.state.compare_and_swap(LOCK, SOME, Ordering::Release) {
263 panic!("unable to release lock");
264 }
265
266 Ok(())
267 }
268
269 /// Put a value into this cell.
270 ///
271 /// Note that this function is infallible but requires `&mut self`. By
272 /// requiring `&mut self` we're guaranteed that no active borrows to this
273 /// cell can exist so we can always fill in the value. This may not always
274 /// be usable, however, as `&mut self` may not be possible to borrow.
275 ///
276 /// # Return value
277 ///
278 /// This function returns the previous value, if any.
279 pub fn replace(&mut self, value: T) -> Option<T> {
280 match mem::replace(self.state.get_mut(), SOME) {
281 NONE | SOME => {}
282 _ => panic!("cell in inconsistent state"),
283 }
284 mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
285 }
286
287 /// Test whether this cell has been previously filled.
288 pub fn filled(&self) -> bool {
289 self.state.load(Ordering::Acquire) == SOME
290 }
291
292 /// Borrows the contents of this lazy cell for the duration of the cell
293 /// itself.
294 ///
295 /// This function will return `Some` if the cell has been previously
296 /// initialized, and `None` if it has not yet been initialized.
297 pub fn borrow(&self) -> Option<&T> {
298 match self.state.load(Ordering::Acquire) {
299 SOME => unsafe { &*self.inner.get() }.as_ref(),
300 _ => None,
301 }
302 }
303
304 /// Consumes this `LazyCell`, returning the underlying value.
305 pub fn into_inner(self) -> Option<T> {
306 // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
307 // function. This unsafe can be removed when supporting Rust older than
308 // 1.25 is not needed.
309 #[allow(unused_unsafe)]
310 unsafe { self.inner.into_inner() }
311 }
312}
313
314impl<T: Copy> AtomicLazyCell<T> {
315 /// Returns a copy of the contents of the lazy cell.
316 ///
317 /// This function will return `Some` if the cell has been previously initialized,
318 /// and `None` if it has not yet been initialized.
319 pub fn get(&self) -> Option<T> {
320 match self.state.load(Ordering::Acquire) {
321 SOME => unsafe { *self.inner.get() },
322 _ => None,
323 }
324 }
325}
326
327impl<T: Clone> Clone for AtomicLazyCell<T> {
328 /// Create a clone of this `AtomicLazyCell`
329 ///
330 /// If self has not been initialized, returns an uninitialized `AtomicLazyCell`
331 /// otherwise returns an `AtomicLazyCell` already initialized with a clone of the
332 /// contents of self.
333 fn clone(&self) -> AtomicLazyCell<T> {
334 self.borrow().map_or(
335 Self::NONE,
336 |v| AtomicLazyCell {
337 inner: UnsafeCell::new(Some(v.clone())),
338 state: AtomicUsize::new(SOME),
339 }
340 )
341 }
342}
343
344unsafe impl<T: Sync + Send> Sync for AtomicLazyCell<T> {}
345
346unsafe impl<T: Send> Send for AtomicLazyCell<T> {}
347
348#[cfg(test)]
349mod tests {
350 use super::{AtomicLazyCell, LazyCell};
351
352 #[test]
353 fn test_borrow_from_empty() {
354 let lazycell: LazyCell<usize> = LazyCell::new();
355
356 let value = lazycell.borrow();
357 assert_eq!(value, None);
358
359 let value = lazycell.get();
360 assert_eq!(value, None);
361 }
362
363 #[test]
364 fn test_fill_and_borrow() {
365 let lazycell = LazyCell::new();
366
367 assert!(!lazycell.filled());
368 lazycell.fill(1).unwrap();
369 assert!(lazycell.filled());
370
371 let value = lazycell.borrow();
372 assert_eq!(value, Some(&1));
373
374 let value = lazycell.get();
375 assert_eq!(value, Some(1));
376 }
377
378 #[test]
379 fn test_borrow_mut() {
380 let mut lazycell = LazyCell::new();
381 assert!(lazycell.borrow_mut().is_none());
382
383 lazycell.fill(1).unwrap();
384 assert_eq!(lazycell.borrow_mut(), Some(&mut 1));
385
386 *lazycell.borrow_mut().unwrap() = 2;
387 assert_eq!(lazycell.borrow_mut(), Some(&mut 2));
388
389 // official way to reset the cell
390 lazycell = LazyCell::new();
391 assert!(lazycell.borrow_mut().is_none());
392 }
393
394 #[test]
395 fn test_already_filled_error() {
396 let lazycell = LazyCell::new();
397
398 lazycell.fill(1).unwrap();
399 assert_eq!(lazycell.fill(1), Err(1));
400 }
401
402 #[test]
403 fn test_borrow_with() {
404 let lazycell = LazyCell::new();
405
406 let value = lazycell.borrow_with(|| 1);
407 assert_eq!(&1, value);
408 }
409
410 #[test]
411 fn test_borrow_with_already_filled() {
412 let lazycell = LazyCell::new();
413 lazycell.fill(1).unwrap();
414
415 let value = lazycell.borrow_with(|| 1);
416 assert_eq!(&1, value);
417 }
418
419 #[test]
420 fn test_borrow_with_not_called_when_filled() {
421 let lazycell = LazyCell::new();
422
423 lazycell.fill(1).unwrap();
424
425 let value = lazycell.borrow_with(|| 2);
426 assert_eq!(&1, value);
427 }
428
429 #[test]
430 #[should_panic]
431 fn test_borrow_with_sound_with_reentrancy() {
432 // Kudos to dbaupp for discovering this issue
433 // https://www.reddit.com/r/rust/comments/5vs9rt/lazycell_a_rust_library_providing_a_lazilyfilled/de527xm/
434 let lazycell: LazyCell<Box<i32>> = LazyCell::new();
435
436 let mut reference: Option<&i32> = None;
437
438 lazycell.borrow_with(|| {
439 let _ = lazycell.fill(Box::new(1));
440 reference = lazycell.borrow().map(|r| &**r);
441 Box::new(2)
442 });
443 }
444
445 #[test]
446 fn test_borrow_mut_with() {
447 let mut lazycell = LazyCell::new();
448
449 {
450 let value = lazycell.borrow_mut_with(|| 1);
451 assert_eq!(&mut 1, value);
452 *value = 2;
453 }
454 assert_eq!(&2, lazycell.borrow().unwrap());
455 }
456
457 #[test]
458 fn test_borrow_mut_with_already_filled() {
459 let mut lazycell = LazyCell::new();
460 lazycell.fill(1).unwrap();
461
462 let value = lazycell.borrow_mut_with(|| 1);
463 assert_eq!(&1, value);
464 }
465
466 #[test]
467 fn test_borrow_mut_with_not_called_when_filled() {
468 let mut lazycell = LazyCell::new();
469
470 lazycell.fill(1).unwrap();
471
472 let value = lazycell.borrow_mut_with(|| 2);
473 assert_eq!(&1, value);
474 }
475
476 #[test]
477 fn test_try_borrow_with_ok() {
478 let lazycell = LazyCell::new();
479 let result = lazycell.try_borrow_with::<(), _>(|| Ok(1));
480 assert_eq!(result, Ok(&1));
481 }
482
483 #[test]
484 fn test_try_borrow_with_err() {
485 let lazycell = LazyCell::<()>::new();
486 let result = lazycell.try_borrow_with(|| Err(1));
487 assert_eq!(result, Err(1));
488 }
489
490 #[test]
491 fn test_try_borrow_with_already_filled() {
492 let lazycell = LazyCell::new();
493 lazycell.fill(1).unwrap();
494 let result = lazycell.try_borrow_with::<(), _>(|| unreachable!());
495 assert_eq!(result, Ok(&1));
496 }
497
498 #[test]
499 #[should_panic]
500 fn test_try_borrow_with_sound_with_reentrancy() {
501 let lazycell: LazyCell<Box<i32>> = LazyCell::new();
502
503 let mut reference: Option<&i32> = None;
504
505 let _ = lazycell.try_borrow_with::<(), _>(|| {
506 let _ = lazycell.fill(Box::new(1));
507 reference = lazycell.borrow().map(|r| &**r);
508 Ok(Box::new(2))
509 });
510 }
511
512 #[test]
513 fn test_try_borrow_mut_with_ok() {
514 let mut lazycell = LazyCell::new();
515 {
516 let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1));
517 assert_eq!(result, Ok(&mut 1));
518 *result.unwrap() = 2;
519 }
520 assert_eq!(&mut 2, lazycell.borrow().unwrap());
521 }
522
523 #[test]
524 fn test_try_borrow_mut_with_err() {
525 let mut lazycell = LazyCell::<()>::new();
526 let result = lazycell.try_borrow_mut_with(|| Err(1));
527 assert_eq!(result, Err(1));
528 }
529
530 #[test]
531 fn test_try_borrow_mut_with_already_filled() {
532 let mut lazycell = LazyCell::new();
533 lazycell.fill(1).unwrap();
534 let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!());
535 assert_eq!(result, Ok(&mut 1));
536 }
537
538 #[test]
539 fn test_into_inner() {
540 let lazycell = LazyCell::new();
541
542 lazycell.fill(1).unwrap();
543 let value = lazycell.into_inner();
544 assert_eq!(value, Some(1));
545 }
546
547 #[test]
548 fn test_atomic_borrow_from_empty() {
549 let lazycell: AtomicLazyCell<usize> = AtomicLazyCell::new();
550
551 let value = lazycell.borrow();
552 assert_eq!(value, None);
553
554 let value = lazycell.get();
555 assert_eq!(value, None);
556 }
557
558 #[test]
559 fn test_atomic_fill_and_borrow() {
560 let lazycell = AtomicLazyCell::new();
561
562 assert!(!lazycell.filled());
563 lazycell.fill(1).unwrap();
564 assert!(lazycell.filled());
565
566 let value = lazycell.borrow();
567 assert_eq!(value, Some(&1));
568
569 let value = lazycell.get();
570 assert_eq!(value, Some(1));
571 }
572
573 #[test]
574 fn test_atomic_already_filled_panic() {
575 let lazycell = AtomicLazyCell::new();
576
577 lazycell.fill(1).unwrap();
578 assert_eq!(1, lazycell.fill(1).unwrap_err());
579 }
580
581 #[test]
582 fn test_atomic_into_inner() {
583 let lazycell = AtomicLazyCell::new();
584
585 lazycell.fill(1).unwrap();
586 let value = lazycell.into_inner();
587 assert_eq!(value, Some(1));
588 }
589
590 #[test]
591 fn normal_replace() {
592 let mut cell = LazyCell::new();
593 assert_eq!(cell.fill(1), Ok(()));
594 assert_eq!(cell.replace(2), Some(1));
595 assert_eq!(cell.replace(3), Some(2));
596 assert_eq!(cell.borrow(), Some(&3));
597
598 let mut cell = LazyCell::new();
599 assert_eq!(cell.replace(2), None);
600 }
601
602 #[test]
603 fn atomic_replace() {
604 let mut cell = AtomicLazyCell::new();
605 assert_eq!(cell.fill(1), Ok(()));
606 assert_eq!(cell.replace(2), Some(1));
607 assert_eq!(cell.replace(3), Some(2));
608 assert_eq!(cell.borrow(), Some(&3));
609 }
610
611 #[test]
612 fn clone() {
613 let mut cell = LazyCell::new();
614 let clone1 = cell.clone();
615 assert_eq!(clone1.borrow(), None);
616 assert_eq!(cell.fill(1), Ok(()));
617 let mut clone2 = cell.clone();
618 assert_eq!(clone1.borrow(), None);
619 assert_eq!(clone2.borrow(), Some(&1));
620 assert_eq!(cell.replace(2), Some(1));
621 assert_eq!(clone1.borrow(), None);
622 assert_eq!(clone2.borrow(), Some(&1));
623 assert_eq!(clone1.fill(3), Ok(()));
624 assert_eq!(clone2.replace(4), Some(1));
625 assert_eq!(clone1.borrow(), Some(&3));
626 assert_eq!(clone2.borrow(), Some(&4));
627 assert_eq!(cell.borrow(), Some(&2));
628 }
629
630 #[test]
631 fn clone_atomic() {
632 let mut cell = AtomicLazyCell::new();
633 let clone1 = cell.clone();
634 assert_eq!(clone1.borrow(), None);
635 assert_eq!(cell.fill(1), Ok(()));
636 let mut clone2 = cell.clone();
637 assert_eq!(clone1.borrow(), None);
638 assert_eq!(clone2.borrow(), Some(&1));
639 assert_eq!(cell.replace(2), Some(1));
640 assert_eq!(clone1.borrow(), None);
641 assert_eq!(clone2.borrow(), Some(&1));
642 assert_eq!(clone1.fill(3), Ok(()));
643 assert_eq!(clone2.replace(4), Some(1));
644 assert_eq!(clone1.borrow(), Some(&3));
645 assert_eq!(clone2.borrow(), Some(&4));
646 assert_eq!(cell.borrow(), Some(&2));
647 }
648}