it.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. mod unsync {
  2. use core::{
  3. cell::Cell,
  4. sync::atomic::{AtomicUsize, Ordering::SeqCst},
  5. };
  6. use once_cell::unsync::{Lazy, OnceCell};
  7. #[test]
  8. fn once_cell() {
  9. let c = OnceCell::new();
  10. assert!(c.get().is_none());
  11. c.get_or_init(|| 92);
  12. assert_eq!(c.get(), Some(&92));
  13. c.get_or_init(|| panic!("Kabom!"));
  14. assert_eq!(c.get(), Some(&92));
  15. }
  16. #[test]
  17. fn once_cell_with_value() {
  18. const CELL: OnceCell<i32> = OnceCell::with_value(12);
  19. let cell = CELL;
  20. assert_eq!(cell.get(), Some(&12));
  21. }
  22. #[test]
  23. fn once_cell_get_mut() {
  24. let mut c = OnceCell::new();
  25. assert!(c.get_mut().is_none());
  26. c.set(90).unwrap();
  27. *c.get_mut().unwrap() += 2;
  28. assert_eq!(c.get_mut(), Some(&mut 92));
  29. }
  30. #[test]
  31. fn once_cell_drop() {
  32. static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
  33. struct Dropper;
  34. impl Drop for Dropper {
  35. fn drop(&mut self) {
  36. DROP_CNT.fetch_add(1, SeqCst);
  37. }
  38. }
  39. let x = OnceCell::new();
  40. x.get_or_init(|| Dropper);
  41. assert_eq!(DROP_CNT.load(SeqCst), 0);
  42. drop(x);
  43. assert_eq!(DROP_CNT.load(SeqCst), 1);
  44. }
  45. #[test]
  46. fn unsync_once_cell_drop_empty() {
  47. let x = OnceCell::<String>::new();
  48. drop(x);
  49. }
  50. #[test]
  51. fn clone() {
  52. let s = OnceCell::new();
  53. let c = s.clone();
  54. assert!(c.get().is_none());
  55. s.set("hello".to_string()).unwrap();
  56. let c = s.clone();
  57. assert_eq!(c.get().map(String::as_str), Some("hello"));
  58. }
  59. #[test]
  60. fn from_impl() {
  61. assert_eq!(OnceCell::from("value").get(), Some(&"value"));
  62. assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
  63. }
  64. #[test]
  65. fn partialeq_impl() {
  66. assert!(OnceCell::from("value") == OnceCell::from("value"));
  67. assert!(OnceCell::from("foo") != OnceCell::from("bar"));
  68. assert!(OnceCell::<String>::new() == OnceCell::new());
  69. assert!(OnceCell::<String>::new() != OnceCell::from("value".to_owned()));
  70. }
  71. #[test]
  72. fn into_inner() {
  73. let cell: OnceCell<String> = OnceCell::new();
  74. assert_eq!(cell.into_inner(), None);
  75. let cell = OnceCell::new();
  76. cell.set("hello".to_string()).unwrap();
  77. assert_eq!(cell.into_inner(), Some("hello".to_string()));
  78. }
  79. #[test]
  80. fn debug_impl() {
  81. let cell = OnceCell::new();
  82. assert_eq!(format!("{:?}", cell), "OnceCell(Uninit)");
  83. cell.set("hello".to_string()).unwrap();
  84. assert_eq!(format!("{:?}", cell), "OnceCell(\"hello\")");
  85. }
  86. #[test]
  87. fn lazy_new() {
  88. let called = Cell::new(0);
  89. let x = Lazy::new(|| {
  90. called.set(called.get() + 1);
  91. 92
  92. });
  93. assert_eq!(called.get(), 0);
  94. let y = *x - 30;
  95. assert_eq!(y, 62);
  96. assert_eq!(called.get(), 1);
  97. let y = *x - 30;
  98. assert_eq!(y, 62);
  99. assert_eq!(called.get(), 1);
  100. }
  101. #[test]
  102. fn lazy_deref_mut() {
  103. let called = Cell::new(0);
  104. let mut x = Lazy::new(|| {
  105. called.set(called.get() + 1);
  106. 92
  107. });
  108. assert_eq!(called.get(), 0);
  109. let y = *x - 30;
  110. assert_eq!(y, 62);
  111. assert_eq!(called.get(), 1);
  112. *x /= 2;
  113. assert_eq!(*x, 46);
  114. assert_eq!(called.get(), 1);
  115. }
  116. #[test]
  117. fn lazy_default() {
  118. static CALLED: AtomicUsize = AtomicUsize::new(0);
  119. struct Foo(u8);
  120. impl Default for Foo {
  121. fn default() -> Self {
  122. CALLED.fetch_add(1, SeqCst);
  123. Foo(42)
  124. }
  125. }
  126. let lazy: Lazy<std::sync::Mutex<Foo>> = <_>::default();
  127. assert_eq!(CALLED.load(SeqCst), 0);
  128. assert_eq!(lazy.lock().unwrap().0, 42);
  129. assert_eq!(CALLED.load(SeqCst), 1);
  130. lazy.lock().unwrap().0 = 21;
  131. assert_eq!(lazy.lock().unwrap().0, 21);
  132. assert_eq!(CALLED.load(SeqCst), 1);
  133. }
  134. #[test]
  135. fn lazy_into_value() {
  136. let l: Lazy<i32, _> = Lazy::new(|| panic!());
  137. assert!(matches!(Lazy::into_value(l), Err(_)));
  138. let l = Lazy::new(|| -> i32 { 92 });
  139. Lazy::force(&l);
  140. assert!(matches!(Lazy::into_value(l), Ok(92)));
  141. }
  142. #[test]
  143. #[cfg(feature = "std")]
  144. fn lazy_poisoning() {
  145. let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
  146. for _ in 0..2 {
  147. let res = std::panic::catch_unwind(|| x.len());
  148. assert!(res.is_err());
  149. }
  150. }
  151. #[test]
  152. fn aliasing_in_get() {
  153. let x = OnceCell::new();
  154. x.set(42).unwrap();
  155. let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
  156. let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>` |
  157. println!("{}", at_x); // <------- up until here ---------------------------+
  158. }
  159. #[test]
  160. #[should_panic(expected = "reentrant init")]
  161. fn reentrant_init() {
  162. let x: OnceCell<Box<i32>> = OnceCell::new();
  163. let dangling_ref: Cell<Option<&i32>> = Cell::new(None);
  164. x.get_or_init(|| {
  165. let r = x.get_or_init(|| Box::new(92));
  166. dangling_ref.set(Some(r));
  167. Box::new(62)
  168. });
  169. eprintln!("use after free: {:?}", dangling_ref.get().unwrap());
  170. }
  171. #[test]
  172. // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669
  173. fn arrrrrrrrrrrrrrrrrrrrrr() {
  174. let cell = OnceCell::new();
  175. {
  176. let s = String::new();
  177. cell.set(&s).unwrap();
  178. }
  179. }
  180. }
  181. #[cfg(feature = "std")]
  182. mod sync {
  183. use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
  184. use crossbeam_utils::thread::scope;
  185. use once_cell::sync::{Lazy, OnceCell};
  186. #[test]
  187. fn once_cell() {
  188. let c = OnceCell::new();
  189. assert!(c.get().is_none());
  190. scope(|s| {
  191. s.spawn(|_| {
  192. c.get_or_init(|| 92);
  193. assert_eq!(c.get(), Some(&92));
  194. });
  195. })
  196. .unwrap();
  197. c.get_or_init(|| panic!("Kabom!"));
  198. assert_eq!(c.get(), Some(&92));
  199. }
  200. #[test]
  201. fn once_cell_with_value() {
  202. static CELL: OnceCell<i32> = OnceCell::with_value(12);
  203. assert_eq!(CELL.get(), Some(&12));
  204. }
  205. #[test]
  206. fn once_cell_get_mut() {
  207. let mut c = OnceCell::new();
  208. assert!(c.get_mut().is_none());
  209. c.set(90).unwrap();
  210. *c.get_mut().unwrap() += 2;
  211. assert_eq!(c.get_mut(), Some(&mut 92));
  212. }
  213. #[test]
  214. fn once_cell_get_unchecked() {
  215. let c = OnceCell::new();
  216. c.set(92).unwrap();
  217. unsafe {
  218. assert_eq!(c.get_unchecked(), &92);
  219. }
  220. }
  221. #[test]
  222. fn once_cell_drop() {
  223. static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
  224. struct Dropper;
  225. impl Drop for Dropper {
  226. fn drop(&mut self) {
  227. DROP_CNT.fetch_add(1, SeqCst);
  228. }
  229. }
  230. let x = OnceCell::new();
  231. scope(|s| {
  232. s.spawn(|_| {
  233. x.get_or_init(|| Dropper);
  234. assert_eq!(DROP_CNT.load(SeqCst), 0);
  235. drop(x);
  236. });
  237. })
  238. .unwrap();
  239. assert_eq!(DROP_CNT.load(SeqCst), 1);
  240. }
  241. #[test]
  242. fn once_cell_drop_empty() {
  243. let x = OnceCell::<String>::new();
  244. drop(x);
  245. }
  246. #[test]
  247. fn clone() {
  248. let s = OnceCell::new();
  249. let c = s.clone();
  250. assert!(c.get().is_none());
  251. s.set("hello".to_string()).unwrap();
  252. let c = s.clone();
  253. assert_eq!(c.get().map(String::as_str), Some("hello"));
  254. }
  255. #[test]
  256. fn get_or_try_init() {
  257. let cell: OnceCell<String> = OnceCell::new();
  258. assert!(cell.get().is_none());
  259. let res =
  260. std::panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
  261. assert!(res.is_err());
  262. assert!(cell.get().is_none());
  263. assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
  264. assert_eq!(
  265. cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())),
  266. Ok(&"hello".to_string())
  267. );
  268. assert_eq!(cell.get(), Some(&"hello".to_string()));
  269. }
  270. #[test]
  271. fn wait() {
  272. let cell: OnceCell<String> = OnceCell::new();
  273. scope(|s| {
  274. s.spawn(|_| cell.set("hello".to_string()));
  275. let greeting = cell.wait();
  276. assert_eq!(greeting, "hello")
  277. })
  278. .unwrap();
  279. }
  280. #[test]
  281. #[cfg_attr(miri, ignore)] // miri doesn't support Barrier
  282. fn get_or_init_stress() {
  283. use std::sync::Barrier;
  284. let n_threads = 1_000;
  285. let n_cells = 1_000;
  286. let cells: Vec<_> = std::iter::repeat_with(|| (Barrier::new(n_threads), OnceCell::new()))
  287. .take(n_cells)
  288. .collect();
  289. scope(|s| {
  290. for t in 0..n_threads {
  291. let cells = &cells;
  292. s.spawn(move |_| {
  293. for (i, (b, s)) in cells.iter().enumerate() {
  294. b.wait();
  295. let j = if t % 2 == 0 { s.wait() } else { s.get_or_init(|| i) };
  296. assert_eq!(*j, i);
  297. }
  298. });
  299. }
  300. })
  301. .unwrap();
  302. }
  303. #[test]
  304. fn from_impl() {
  305. assert_eq!(OnceCell::from("value").get(), Some(&"value"));
  306. assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
  307. }
  308. #[test]
  309. fn partialeq_impl() {
  310. assert!(OnceCell::from("value") == OnceCell::from("value"));
  311. assert!(OnceCell::from("foo") != OnceCell::from("bar"));
  312. assert!(OnceCell::<String>::new() == OnceCell::new());
  313. assert!(OnceCell::<String>::new() != OnceCell::from("value".to_owned()));
  314. }
  315. #[test]
  316. fn into_inner() {
  317. let cell: OnceCell<String> = OnceCell::new();
  318. assert_eq!(cell.into_inner(), None);
  319. let cell = OnceCell::new();
  320. cell.set("hello".to_string()).unwrap();
  321. assert_eq!(cell.into_inner(), Some("hello".to_string()));
  322. }
  323. #[test]
  324. fn debug_impl() {
  325. let cell = OnceCell::new();
  326. assert_eq!(format!("{:#?}", cell), "OnceCell(Uninit)");
  327. cell.set(vec!["hello", "world"]).unwrap();
  328. assert_eq!(
  329. format!("{:#?}", cell),
  330. r#"OnceCell(
  331. [
  332. "hello",
  333. "world",
  334. ],
  335. )"#
  336. );
  337. }
  338. #[test]
  339. #[cfg_attr(miri, ignore)] // miri doesn't support processes
  340. fn reentrant_init() {
  341. let examples_dir = {
  342. let mut exe = std::env::current_exe().unwrap();
  343. exe.pop();
  344. exe.pop();
  345. exe.push("examples");
  346. exe
  347. };
  348. let bin = examples_dir
  349. .join("reentrant_init_deadlocks")
  350. .with_extension(std::env::consts::EXE_EXTENSION);
  351. let mut guard = Guard { child: std::process::Command::new(bin).spawn().unwrap() };
  352. std::thread::sleep(std::time::Duration::from_secs(2));
  353. let status = guard.child.try_wait().unwrap();
  354. assert!(status.is_none());
  355. struct Guard {
  356. child: std::process::Child,
  357. }
  358. impl Drop for Guard {
  359. fn drop(&mut self) {
  360. let _ = self.child.kill();
  361. }
  362. }
  363. }
  364. #[test]
  365. fn lazy_new() {
  366. let called = AtomicUsize::new(0);
  367. let x = Lazy::new(|| {
  368. called.fetch_add(1, SeqCst);
  369. 92
  370. });
  371. assert_eq!(called.load(SeqCst), 0);
  372. scope(|s| {
  373. s.spawn(|_| {
  374. let y = *x - 30;
  375. assert_eq!(y, 62);
  376. assert_eq!(called.load(SeqCst), 1);
  377. });
  378. })
  379. .unwrap();
  380. let y = *x - 30;
  381. assert_eq!(y, 62);
  382. assert_eq!(called.load(SeqCst), 1);
  383. }
  384. #[test]
  385. fn lazy_deref_mut() {
  386. let called = AtomicUsize::new(0);
  387. let mut x = Lazy::new(|| {
  388. called.fetch_add(1, SeqCst);
  389. 92
  390. });
  391. assert_eq!(called.load(SeqCst), 0);
  392. let y = *x - 30;
  393. assert_eq!(y, 62);
  394. assert_eq!(called.load(SeqCst), 1);
  395. *x /= 2;
  396. assert_eq!(*x, 46);
  397. assert_eq!(called.load(SeqCst), 1);
  398. }
  399. #[test]
  400. fn lazy_default() {
  401. static CALLED: AtomicUsize = AtomicUsize::new(0);
  402. struct Foo(u8);
  403. impl Default for Foo {
  404. fn default() -> Self {
  405. CALLED.fetch_add(1, SeqCst);
  406. Foo(42)
  407. }
  408. }
  409. let lazy: Lazy<std::sync::Mutex<Foo>> = <_>::default();
  410. assert_eq!(CALLED.load(SeqCst), 0);
  411. assert_eq!(lazy.lock().unwrap().0, 42);
  412. assert_eq!(CALLED.load(SeqCst), 1);
  413. lazy.lock().unwrap().0 = 21;
  414. assert_eq!(lazy.lock().unwrap().0, 21);
  415. assert_eq!(CALLED.load(SeqCst), 1);
  416. }
  417. #[test]
  418. fn static_lazy() {
  419. static XS: Lazy<Vec<i32>> = Lazy::new(|| {
  420. let mut xs = Vec::new();
  421. xs.push(1);
  422. xs.push(2);
  423. xs.push(3);
  424. xs
  425. });
  426. scope(|s| {
  427. s.spawn(|_| {
  428. assert_eq!(&*XS, &vec![1, 2, 3]);
  429. });
  430. })
  431. .unwrap();
  432. assert_eq!(&*XS, &vec![1, 2, 3]);
  433. }
  434. #[test]
  435. fn static_lazy_via_fn() {
  436. fn xs() -> &'static Vec<i32> {
  437. static XS: OnceCell<Vec<i32>> = OnceCell::new();
  438. XS.get_or_init(|| {
  439. let mut xs = Vec::new();
  440. xs.push(1);
  441. xs.push(2);
  442. xs.push(3);
  443. xs
  444. })
  445. }
  446. assert_eq!(xs(), &vec![1, 2, 3]);
  447. }
  448. #[test]
  449. fn lazy_into_value() {
  450. let l: Lazy<i32, _> = Lazy::new(|| panic!());
  451. assert!(matches!(Lazy::into_value(l), Err(_)));
  452. let l = Lazy::new(|| -> i32 { 92 });
  453. Lazy::force(&l);
  454. assert!(matches!(Lazy::into_value(l), Ok(92)));
  455. }
  456. #[test]
  457. fn lazy_poisoning() {
  458. let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
  459. for _ in 0..2 {
  460. let res = std::panic::catch_unwind(|| x.len());
  461. assert!(res.is_err());
  462. }
  463. }
  464. #[test]
  465. fn once_cell_is_sync_send() {
  466. fn assert_traits<T: Send + Sync>() {}
  467. assert_traits::<OnceCell<String>>();
  468. assert_traits::<Lazy<String>>();
  469. }
  470. #[test]
  471. fn eval_once_macro() {
  472. macro_rules! eval_once {
  473. (|| -> $ty:ty {
  474. $($body:tt)*
  475. }) => {{
  476. static ONCE_CELL: OnceCell<$ty> = OnceCell::new();
  477. fn init() -> $ty {
  478. $($body)*
  479. }
  480. ONCE_CELL.get_or_init(init)
  481. }};
  482. }
  483. let fib: &'static Vec<i32> = eval_once! {
  484. || -> Vec<i32> {
  485. let mut res = vec![1, 1];
  486. for i in 0..10 {
  487. let next = res[i] + res[i + 1];
  488. res.push(next);
  489. }
  490. res
  491. }
  492. };
  493. assert_eq!(fib[5], 8)
  494. }
  495. #[test]
  496. #[cfg_attr(miri, ignore)] // FIXME: deadlocks, likely caused by https://github.com/rust-lang/miri/issues/1388
  497. fn once_cell_does_not_leak_partially_constructed_boxes() {
  498. let n_tries = 100;
  499. let n_readers = 10;
  500. let n_writers = 3;
  501. const MSG: &str = "Hello, World";
  502. for _ in 0..n_tries {
  503. let cell: OnceCell<String> = OnceCell::new();
  504. scope(|scope| {
  505. for _ in 0..n_readers {
  506. scope.spawn(|_| loop {
  507. if let Some(msg) = cell.get() {
  508. assert_eq!(msg, MSG);
  509. break;
  510. }
  511. });
  512. }
  513. for _ in 0..n_writers {
  514. let _ = scope.spawn(|_| cell.set(MSG.to_owned()));
  515. }
  516. })
  517. .unwrap()
  518. }
  519. }
  520. #[test]
  521. #[cfg_attr(miri, ignore)] // miri doesn't support Barrier
  522. fn get_does_not_block() {
  523. use std::sync::Barrier;
  524. let cell = OnceCell::new();
  525. let barrier = Barrier::new(2);
  526. scope(|scope| {
  527. scope.spawn(|_| {
  528. cell.get_or_init(|| {
  529. barrier.wait();
  530. barrier.wait();
  531. "hello".to_string()
  532. });
  533. });
  534. barrier.wait();
  535. assert_eq!(cell.get(), None);
  536. barrier.wait();
  537. })
  538. .unwrap();
  539. assert_eq!(cell.get(), Some(&"hello".to_string()));
  540. }
  541. #[test]
  542. // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669
  543. fn arrrrrrrrrrrrrrrrrrrrrr() {
  544. let cell = OnceCell::new();
  545. {
  546. let s = String::new();
  547. cell.set(&s).unwrap();
  548. }
  549. }
  550. }
  551. #[cfg(feature = "race")]
  552. mod race {
  553. use std::{
  554. num::NonZeroUsize,
  555. sync::{
  556. atomic::{AtomicUsize, Ordering::SeqCst},
  557. Barrier,
  558. },
  559. };
  560. use crossbeam_utils::thread::scope;
  561. use once_cell::race::{OnceBool, OnceNonZeroUsize};
  562. #[test]
  563. fn once_non_zero_usize_smoke_test() {
  564. let cnt = AtomicUsize::new(0);
  565. let cell = OnceNonZeroUsize::new();
  566. let val = NonZeroUsize::new(92).unwrap();
  567. scope(|s| {
  568. s.spawn(|_| {
  569. assert_eq!(
  570. cell.get_or_init(|| {
  571. cnt.fetch_add(1, SeqCst);
  572. val
  573. }),
  574. val
  575. );
  576. assert_eq!(cnt.load(SeqCst), 1);
  577. assert_eq!(
  578. cell.get_or_init(|| {
  579. cnt.fetch_add(1, SeqCst);
  580. val
  581. }),
  582. val
  583. );
  584. assert_eq!(cnt.load(SeqCst), 1);
  585. });
  586. })
  587. .unwrap();
  588. assert_eq!(cell.get(), Some(val));
  589. assert_eq!(cnt.load(SeqCst), 1);
  590. }
  591. #[test]
  592. fn once_non_zero_usize_set() {
  593. let val1 = NonZeroUsize::new(92).unwrap();
  594. let val2 = NonZeroUsize::new(62).unwrap();
  595. let cell = OnceNonZeroUsize::new();
  596. assert!(cell.set(val1).is_ok());
  597. assert_eq!(cell.get(), Some(val1));
  598. assert!(cell.set(val2).is_err());
  599. assert_eq!(cell.get(), Some(val1));
  600. }
  601. #[test]
  602. fn once_non_zero_usize_first_wins() {
  603. let val1 = NonZeroUsize::new(92).unwrap();
  604. let val2 = NonZeroUsize::new(62).unwrap();
  605. let cell = OnceNonZeroUsize::new();
  606. let b1 = Barrier::new(2);
  607. let b2 = Barrier::new(2);
  608. let b3 = Barrier::new(2);
  609. scope(|s| {
  610. s.spawn(|_| {
  611. let r1 = cell.get_or_init(|| {
  612. b1.wait();
  613. b2.wait();
  614. val1
  615. });
  616. assert_eq!(r1, val1);
  617. b3.wait();
  618. });
  619. b1.wait();
  620. s.spawn(|_| {
  621. let r2 = cell.get_or_init(|| {
  622. b2.wait();
  623. b3.wait();
  624. val2
  625. });
  626. assert_eq!(r2, val1);
  627. });
  628. })
  629. .unwrap();
  630. assert_eq!(cell.get(), Some(val1));
  631. }
  632. #[test]
  633. fn once_bool_smoke_test() {
  634. let cnt = AtomicUsize::new(0);
  635. let cell = OnceBool::new();
  636. scope(|s| {
  637. s.spawn(|_| {
  638. assert_eq!(
  639. cell.get_or_init(|| {
  640. cnt.fetch_add(1, SeqCst);
  641. false
  642. }),
  643. false
  644. );
  645. assert_eq!(cnt.load(SeqCst), 1);
  646. assert_eq!(
  647. cell.get_or_init(|| {
  648. cnt.fetch_add(1, SeqCst);
  649. false
  650. }),
  651. false
  652. );
  653. assert_eq!(cnt.load(SeqCst), 1);
  654. });
  655. })
  656. .unwrap();
  657. assert_eq!(cell.get(), Some(false));
  658. assert_eq!(cnt.load(SeqCst), 1);
  659. }
  660. #[test]
  661. fn once_bool_set() {
  662. let cell = OnceBool::new();
  663. assert!(cell.set(false).is_ok());
  664. assert_eq!(cell.get(), Some(false));
  665. assert!(cell.set(true).is_err());
  666. assert_eq!(cell.get(), Some(false));
  667. }
  668. }
  669. #[cfg(all(feature = "race", feature = "alloc"))]
  670. mod race_once_box {
  671. use std::sync::{
  672. atomic::{AtomicUsize, Ordering::SeqCst},
  673. Arc, Barrier,
  674. };
  675. use crossbeam_utils::thread::scope;
  676. use once_cell::race::OnceBox;
  677. #[derive(Default)]
  678. struct Heap {
  679. total: Arc<AtomicUsize>,
  680. }
  681. #[derive(Debug)]
  682. struct Pebble<T> {
  683. val: T,
  684. total: Arc<AtomicUsize>,
  685. }
  686. impl<T> Drop for Pebble<T> {
  687. fn drop(&mut self) {
  688. self.total.fetch_sub(1, SeqCst);
  689. }
  690. }
  691. impl Heap {
  692. fn total(&self) -> usize {
  693. self.total.load(SeqCst)
  694. }
  695. fn new_pebble<T>(&self, val: T) -> Pebble<T> {
  696. self.total.fetch_add(1, SeqCst);
  697. Pebble { val, total: Arc::clone(&self.total) }
  698. }
  699. }
  700. #[test]
  701. fn once_box_smoke_test() {
  702. let heap = Heap::default();
  703. let global_cnt = AtomicUsize::new(0);
  704. let cell = OnceBox::new();
  705. let b = Barrier::new(128);
  706. scope(|s| {
  707. for _ in 0..128 {
  708. s.spawn(|_| {
  709. let local_cnt = AtomicUsize::new(0);
  710. cell.get_or_init(|| {
  711. global_cnt.fetch_add(1, SeqCst);
  712. local_cnt.fetch_add(1, SeqCst);
  713. b.wait();
  714. Box::new(heap.new_pebble(()))
  715. });
  716. assert_eq!(local_cnt.load(SeqCst), 1);
  717. cell.get_or_init(|| {
  718. global_cnt.fetch_add(1, SeqCst);
  719. local_cnt.fetch_add(1, SeqCst);
  720. Box::new(heap.new_pebble(()))
  721. });
  722. assert_eq!(local_cnt.load(SeqCst), 1);
  723. });
  724. }
  725. })
  726. .unwrap();
  727. assert!(cell.get().is_some());
  728. assert!(global_cnt.load(SeqCst) > 10);
  729. assert_eq!(heap.total(), 1);
  730. drop(cell);
  731. assert_eq!(heap.total(), 0);
  732. }
  733. #[test]
  734. fn once_box_set() {
  735. let heap = Heap::default();
  736. let cell = OnceBox::new();
  737. assert!(cell.get().is_none());
  738. assert!(cell.set(Box::new(heap.new_pebble("hello"))).is_ok());
  739. assert_eq!(cell.get().unwrap().val, "hello");
  740. assert_eq!(heap.total(), 1);
  741. assert!(cell.set(Box::new(heap.new_pebble("world"))).is_err());
  742. assert_eq!(cell.get().unwrap().val, "hello");
  743. assert_eq!(heap.total(), 1);
  744. drop(cell);
  745. assert_eq!(heap.total(), 0);
  746. }
  747. #[test]
  748. fn once_box_first_wins() {
  749. let cell = OnceBox::new();
  750. let val1 = 92;
  751. let val2 = 62;
  752. let b1 = Barrier::new(2);
  753. let b2 = Barrier::new(2);
  754. let b3 = Barrier::new(2);
  755. scope(|s| {
  756. s.spawn(|_| {
  757. let r1 = cell.get_or_init(|| {
  758. b1.wait();
  759. b2.wait();
  760. Box::new(val1)
  761. });
  762. assert_eq!(*r1, val1);
  763. b3.wait();
  764. });
  765. b1.wait();
  766. s.spawn(|_| {
  767. let r2 = cell.get_or_init(|| {
  768. b2.wait();
  769. b3.wait();
  770. Box::new(val2)
  771. });
  772. assert_eq!(*r2, val1);
  773. });
  774. })
  775. .unwrap();
  776. assert_eq!(cell.get(), Some(&val1));
  777. }
  778. #[test]
  779. fn once_box_reentrant() {
  780. let cell = OnceBox::new();
  781. let res = cell.get_or_init(|| {
  782. cell.get_or_init(|| Box::new("hello".to_string()));
  783. Box::new("world".to_string())
  784. });
  785. assert_eq!(res, "hello");
  786. }
  787. #[test]
  788. fn once_box_default() {
  789. struct Foo;
  790. let cell: OnceBox<Foo> = Default::default();
  791. assert!(cell.get().is_none());
  792. }
  793. }