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