reference_counted_singleton/
lib.rs1#![doc = include_str!("../README.md")]
2#![doc(html_root_url = "https://docs.rs/reference-counted-singleton/0.1.5")]
3#![warn(unsafe_op_in_unsafe_fn)]
4
5#[cfg(test)]
6mod tests;
7
8use std::error::Error;
9use std::hash::{Hash, Hasher};
10use std::mem::ManuallyDrop;
11use std::ops::Deref;
12use std::sync::{Arc, Mutex};
13
14#[derive(Debug)]
25pub struct RefCountedSingleton<T>(Mutex<Option<Arc<T>>>);
26
27impl<T> Default for RefCountedSingleton<T> {
28 fn default() -> Self {
29 Self(Mutex::new(None))
30 }
31}
32
33impl<T> RefCountedSingleton<T> {
34 pub fn get_or_init<E: Error>(
41 &'_ self,
42 creator: impl FnOnce() -> Result<T, E>,
43 ) -> Result<RCSRef<'_, T>, Option<E>> {
44 if let Ok(mut value) = self.0.lock() {
45 match *value {
46 None => match creator() {
48 Ok(data) => {
49 let data = Arc::new(data);
51 let data_ref = Arc::clone(&data);
52
53 *value = Some(data);
54
55 Ok(RCSRef {
56 data: ManuallyDrop::new(data_ref),
57 rcs: self,
58 })
59 }
60
61 Err(err) => Err(Some(err)),
63 },
64
65 Some(ref data) => Ok(RCSRef {
67 data: ManuallyDrop::new(Arc::clone(data)),
68 rcs: self,
69 }),
70 }
71 } else {
72 Err(None) }
74 }
75
76 pub fn get(&'_ self) -> Option<RCSRef<'_, T>> {
81 self.0.lock().ok().and_then(|value| {
82 value.as_ref().map(|data| RCSRef {
83 data: ManuallyDrop::new(Arc::clone(data)),
84 rcs: self,
85 })
86 })
87 }
88}
89
90#[derive(Debug)]
92pub struct RCSRef<'t, T> {
93 data: ManuallyDrop<Arc<T>>,
94 rcs: &'t RefCountedSingleton<T>,
95}
96
97impl<'t, T: PartialEq> PartialEq for RCSRef<'t, T> {
98 fn eq(&self, other: &Self) -> bool {
99 Arc::as_ref(&self.data).eq(Arc::as_ref(&other.data))
100 }
101}
102
103impl<'t, T: Eq> Eq for RCSRef<'t, T> {}
104
105impl<'t, T: PartialOrd> PartialOrd for RCSRef<'t, T> {
106 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
107 Arc::as_ref(&self.data).partial_cmp(Arc::as_ref(&other.data))
108 }
109}
110
111impl<'t, T: Ord> Ord for RCSRef<'t, T> {
112 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
113 Arc::as_ref(&self.data).cmp(Arc::as_ref(&other.data))
114 }
115}
116
117impl<'t, T: Hash> Hash for RCSRef<'t, T> {
118 fn hash<H: Hasher>(&self, state: &mut H) {
119 Arc::as_ref(&self.data).hash(state)
120 }
121}
122
123impl<'t, T> Deref for RCSRef<'t, T> {
124 type Target = T;
125
126 fn deref(&self) -> &T {
127 Arc::as_ref(&self.data)
128 }
129}
130
131impl<'t, T> Clone for RCSRef<'t, T> {
132 fn clone(&self) -> Self {
133 Self {
134 data: ManuallyDrop::new(Arc::clone(&self.data)),
135 rcs: self.rcs,
136 }
137 }
138}
139
140impl<'t, T> Drop for RCSRef<'t, T> {
141 fn drop(&mut self) {
142 unsafe { ManuallyDrop::drop(&mut self.data) };
145
146 if let Ok(mut value) = self.rcs.0.lock() {
147 if let Some(data) = value.take() {
148 match Arc::try_unwrap(data) {
149 Ok(data) => drop(data),
152
153 Err(data) => *value = Some(data),
156 }
157 }
158 }
159 }
160}