1use std::sync::Arc;
2use std::sync::Mutex;
3use std::sync::OnceLock;
4use std::sync::Weak;
5
6#[derive(Default)]
7pub struct Fixture<T> {
8 once: OnceLock<FixtureState<T>>,
9 lock: Mutex<()>,
10}
11
12impl<T> Fixture<T> {
13 pub const fn new() -> Self {
14 Self {
15 once: OnceLock::new(),
16 lock: Mutex::new(()),
17 }
18 }
19
20 pub fn get_or_init(&self, init: impl Fn() -> T + Send + Sync + 'static) -> Arc<T> {
21 self.once
22 .get_or_init(|| FixtureState::new(init))
23 .get_or_init()
24 }
25
26 pub fn get(&self) -> Arc<T> {
27 self.once.get().expect("Fixture::get").get()
28 }
29
30 pub fn lock(&self) -> impl Drop {
31 self.lock.lock().unwrap()
32 }
33}
34
35struct FixtureState<T> {
36 init: Box<dyn Fn() -> T + Send + Sync>,
37 current: Mutex<Weak<T>>,
38}
39
40impl<T> FixtureState<T> {
41 fn new(init: impl Fn() -> T + Send + Sync + 'static) -> Self {
42 Self {
43 init: Box::new(init),
44 current: Default::default(),
45 }
46 }
47
48 fn get_or_init(&self) -> Arc<T> {
49 let mut current = self.current.lock().expect("FixtureState::current::lock");
50 if let Some(value) = current.upgrade() {
51 return value;
52 }
53 let value = Arc::new((self.init)());
54 *current = Arc::downgrade(&value);
55 return value;
56 }
57
58 fn get(&self) -> Arc<T> {
59 self.current
60 .lock()
61 .expect("FixtureState::current::lock")
62 .upgrade()
63 .expect("FixtureState::get")
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use std::sync::Arc;
70 use std::sync::atomic::AtomicI32;
71 use std::sync::atomic::Ordering::SeqCst;
72
73 use super::Fixture;
74
75 #[test]
76 fn test_fixture() {
77 let a = fixture();
78 assert_eq!(1, *a);
79 let b = fixture();
80 assert_eq!(1, *a);
81 drop(a);
82 drop(b);
83 let c = fixture();
84 assert_eq!(2, *c);
85 }
86
87 fn fixture() -> Arc<i32> {
88 static FIXTURE: Fixture<i32> = Fixture::new();
89 static NEXT: AtomicI32 = AtomicI32::new(1);
90 FIXTURE.get_or_init(|| NEXT.fetch_add(1, SeqCst))
91 }
92}