1 | use std::{ |
2 | cell::Cell, |
3 | sync::atomic::{AtomicUsize, Ordering::SeqCst}, |
4 | thread::scope, |
5 | }; |
6 | |
7 | use once_cell::sync::{Lazy, OnceCell}; |
8 | |
9 | #[test] |
10 | fn lazy_new() { |
11 | let called = AtomicUsize::new(0); |
12 | let x = Lazy::new(|| { |
13 | called.fetch_add(1, SeqCst); |
14 | 92 |
15 | }); |
16 | |
17 | assert_eq!(called.load(SeqCst), 0); |
18 | |
19 | scope(|s| { |
20 | s.spawn(|| { |
21 | let y = *x - 30; |
22 | assert_eq!(y, 62); |
23 | assert_eq!(called.load(SeqCst), 1); |
24 | }); |
25 | }); |
26 | |
27 | let y = *x - 30; |
28 | assert_eq!(y, 62); |
29 | assert_eq!(called.load(SeqCst), 1); |
30 | } |
31 | |
32 | #[test] |
33 | fn lazy_deref_mut() { |
34 | let called = AtomicUsize::new(0); |
35 | let mut x = Lazy::new(|| { |
36 | called.fetch_add(1, SeqCst); |
37 | 92 |
38 | }); |
39 | |
40 | assert_eq!(called.load(SeqCst), 0); |
41 | |
42 | let y = *x - 30; |
43 | assert_eq!(y, 62); |
44 | assert_eq!(called.load(SeqCst), 1); |
45 | |
46 | *x /= 2; |
47 | assert_eq!(*x, 46); |
48 | assert_eq!(called.load(SeqCst), 1); |
49 | } |
50 | |
51 | #[test] |
52 | fn lazy_force_mut() { |
53 | let called = Cell::new(0); |
54 | let mut x = Lazy::new(|| { |
55 | called.set(called.get() + 1); |
56 | 92 |
57 | }); |
58 | assert_eq!(called.get(), 0); |
59 | let v = Lazy::force_mut(&mut x); |
60 | assert_eq!(called.get(), 1); |
61 | |
62 | *v /= 2; |
63 | assert_eq!(*x, 46); |
64 | assert_eq!(called.get(), 1); |
65 | } |
66 | |
67 | #[test] |
68 | fn lazy_get_mut() { |
69 | let called = Cell::new(0); |
70 | let mut x: Lazy<u32, _> = Lazy::new(|| { |
71 | called.set(called.get() + 1); |
72 | 92 |
73 | }); |
74 | |
75 | assert_eq!(called.get(), 0); |
76 | assert_eq!(*x, 92); |
77 | |
78 | let mut_ref: &mut u32 = Lazy::get_mut(&mut x).unwrap(); |
79 | assert_eq!(called.get(), 1); |
80 | |
81 | *mut_ref /= 2; |
82 | assert_eq!(*x, 46); |
83 | assert_eq!(called.get(), 1); |
84 | } |
85 | |
86 | #[test] |
87 | fn lazy_default() { |
88 | static CALLED: AtomicUsize = AtomicUsize::new(0); |
89 | |
90 | struct Foo(u8); |
91 | impl Default for Foo { |
92 | fn default() -> Self { |
93 | CALLED.fetch_add(1, SeqCst); |
94 | Foo(42) |
95 | } |
96 | } |
97 | |
98 | let lazy: Lazy<std::sync::Mutex<Foo>> = <_>::default(); |
99 | |
100 | assert_eq!(CALLED.load(SeqCst), 0); |
101 | |
102 | assert_eq!(lazy.lock().unwrap().0, 42); |
103 | assert_eq!(CALLED.load(SeqCst), 1); |
104 | |
105 | lazy.lock().unwrap().0 = 21; |
106 | |
107 | assert_eq!(lazy.lock().unwrap().0, 21); |
108 | assert_eq!(CALLED.load(SeqCst), 1); |
109 | } |
110 | |
111 | #[test] |
112 | fn static_lazy() { |
113 | static XS: Lazy<Vec<i32>> = Lazy::new(|| { |
114 | let mut xs = Vec::new(); |
115 | xs.push(1); |
116 | xs.push(2); |
117 | xs.push(3); |
118 | xs |
119 | }); |
120 | scope(|s| { |
121 | s.spawn(|| { |
122 | assert_eq!(&*XS, &vec![1, 2, 3]); |
123 | }); |
124 | }); |
125 | assert_eq!(&*XS, &vec![1, 2, 3]); |
126 | } |
127 | |
128 | #[test] |
129 | fn static_lazy_via_fn() { |
130 | fn xs() -> &'static Vec<i32> { |
131 | static XS: OnceCell<Vec<i32>> = OnceCell::new(); |
132 | XS.get_or_init(|| { |
133 | let mut xs = Vec::new(); |
134 | xs.push(1); |
135 | xs.push(2); |
136 | xs.push(3); |
137 | xs |
138 | }) |
139 | } |
140 | assert_eq!(xs(), &vec![1, 2, 3]); |
141 | } |
142 | |
143 | #[test] |
144 | fn lazy_into_value() { |
145 | let l: Lazy<i32, _> = Lazy::new(|| panic!()); |
146 | assert!(matches!(Lazy::into_value(l), Err(_))); |
147 | let l = Lazy::new(|| -> i32 { 92 }); |
148 | Lazy::force(&l); |
149 | assert!(matches!(Lazy::into_value(l), Ok(92))); |
150 | } |
151 | |
152 | #[test] |
153 | fn lazy_poisoning() { |
154 | let x: Lazy<String> = Lazy::new(|| panic!("kaboom" )); |
155 | for _ in 0..2 { |
156 | let res = std::panic::catch_unwind(|| x.len()); |
157 | assert!(res.is_err()); |
158 | } |
159 | } |
160 | |
161 | #[test] |
162 | // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 |
163 | fn arrrrrrrrrrrrrrrrrrrrrr() { |
164 | let lazy: Lazy<&String, _>; |
165 | { |
166 | let s = String::new(); |
167 | lazy = Lazy::new(|| &s); |
168 | _ = *lazy; |
169 | } |
170 | } |
171 | |
172 | #[test] |
173 | fn lazy_is_sync_send() { |
174 | fn assert_traits<T: Send + Sync>() {} |
175 | assert_traits::<Lazy<String>>(); |
176 | } |
177 | |