est_render/utils/
arcrw.rs

1use std::sync::{Arc, RwLock};
2
3#[derive(Clone)]
4pub struct ArcRW<T> {
5    inner: Arc<RwLock<T>>,
6}
7
8impl<T> ArcRW<T> {
9    /// Create a new ArcRW with the given value.
10    pub fn new(value: T) -> ArcRW<T> {
11        ArcRW {
12            inner: Arc::new(RwLock::new(value)),
13        }
14    }
15
16    /// Clone the ArcRW, incrementing the reference count.
17    pub fn clone(&self) -> ArcRW<T> {
18        ArcRW {
19            inner: self.inner.clone(),
20        }
21    }
22
23    /// Try to borrow the value immutably.
24    pub fn try_read(&self) -> Option<std::sync::RwLockReadGuard<T>> {
25        self.inner.try_read().ok()
26    }
27
28    /// Try to borrow the value mutably.
29    pub fn try_write(&self) -> Option<std::sync::RwLockWriteGuard<T>> {
30        self.inner.try_write().ok()
31    }
32
33    /// Borrow the value immutably.
34    pub fn read(&self) -> std::sync::RwLockReadGuard<T> {
35        self.try_read().expect("Failed to acquire read lock")
36    }
37
38    /// Borrow the value mutably.
39    pub fn write(&self) -> std::sync::RwLockWriteGuard<T> {
40        self.try_write().expect("Failed to acquire write lock")
41    }
42
43    /// Wait for the read lock to be available, blocking until it can be acquired.
44    /// In debug mode, this will panic if the read lock is not acquired within 5 seconds.
45    pub fn wait_read(&self) -> std::sync::RwLockReadGuard<T> {
46        #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
47        let now = std::time::Instant::now();
48        loop {
49            if let Ok(guard) = self.inner.try_read() {
50                return guard;
51            }
52
53            #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
54            if now.elapsed().as_secs() > 5 {
55                panic!("wait_read: waited more than 5 seconds to acquire read lock");
56            }
57        }
58    }
59
60    /// Wait for the write lock to be available, blocking until it can be acquired.
61    /// In debug mode, this will panic if the write lock is not acquired within 5 seconds.
62    pub fn wait_write(&self) -> std::sync::RwLockWriteGuard<T> {
63        #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
64        let now = std::time::Instant::now();
65        loop {
66            if let Ok(guard) = self.inner.try_write() {
67                return guard;
68            }
69
70            #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
71            if now.elapsed().as_secs() > 5 {
72                panic!("wait_write: waited more than 5 seconds to acquire write lock");
73            }
74        }
75    }
76
77    /// Try to unwrap the ArcRW, returning the inner value if there are no other references.
78    /// If there are other references, return an ArcRW with the inner value.
79    pub fn into_inner(self) -> Result<T, Self> {
80        let inner = Arc::try_unwrap(self.inner);
81        match inner {
82            Ok(lock) => match lock.into_inner() {
83                Ok(value) => Ok(value),
84                Err(poison_err) => Err(Self {
85                    inner: Arc::new(RwLock::new(poison_err.into_inner())),
86                }),
87            },
88            Err(val) => Err(Self { inner: val }),
89        }
90    }
91}