fragile/
semisticky.rs
1use std::cmp;
2use std::fmt;
3
4use crate::errors::InvalidThreadAccess;
5use crate::fragile::Fragile;
6use crate::sticky::Sticky;
7use std::mem;
8
9enum SemiStickyImpl<T> {
10 Fragile(Fragile<T>),
11 Sticky(Sticky<T>),
12}
13
14pub struct SemiSticky<T> {
20 inner: SemiStickyImpl<T>,
21}
22
23impl<T> SemiSticky<T> {
24 pub fn new(value: T) -> Self {
33 SemiSticky {
34 inner: if mem::needs_drop::<T>() {
35 SemiStickyImpl::Sticky(Sticky::new(value))
36 } else {
37 SemiStickyImpl::Fragile(Fragile::new(value))
38 },
39 }
40 }
41
42 pub fn is_valid(&self) -> bool {
46 match self.inner {
47 SemiStickyImpl::Fragile(ref inner) => inner.is_valid(),
48 SemiStickyImpl::Sticky(ref inner) => inner.is_valid(),
49 }
50 }
51
52 pub fn into_inner(self) -> T {
59 match self.inner {
60 SemiStickyImpl::Fragile(inner) => inner.into_inner(),
61 SemiStickyImpl::Sticky(inner) => inner.into_inner(),
62 }
63 }
64
65 pub fn try_into_inner(self) -> Result<T, Self> {
71 match self.inner {
72 SemiStickyImpl::Fragile(inner) => inner.try_into_inner().map_err(|inner| SemiSticky {
73 inner: SemiStickyImpl::Fragile(inner),
74 }),
75 SemiStickyImpl::Sticky(inner) => inner.try_into_inner().map_err(|inner| SemiSticky {
76 inner: SemiStickyImpl::Sticky(inner),
77 }),
78 }
79 }
80
81 pub fn get(&self) -> &T {
88 match self.inner {
89 SemiStickyImpl::Fragile(ref inner) => inner.get(),
90 SemiStickyImpl::Sticky(ref inner) => inner.get(),
91 }
92 }
93
94 pub fn get_mut(&mut self) -> &mut T {
101 match self.inner {
102 SemiStickyImpl::Fragile(ref mut inner) => inner.get_mut(),
103 SemiStickyImpl::Sticky(ref mut inner) => inner.get_mut(),
104 }
105 }
106
107 pub fn try_get(&self) -> Result<&T, InvalidThreadAccess> {
111 match self.inner {
112 SemiStickyImpl::Fragile(ref inner) => inner.try_get(),
113 SemiStickyImpl::Sticky(ref inner) => inner.try_get(),
114 }
115 }
116
117 pub fn try_get_mut(&mut self) -> Result<&mut T, InvalidThreadAccess> {
121 match self.inner {
122 SemiStickyImpl::Fragile(ref mut inner) => inner.try_get_mut(),
123 SemiStickyImpl::Sticky(ref mut inner) => inner.try_get_mut(),
124 }
125 }
126}
127
128impl<T> From<T> for SemiSticky<T> {
129 #[inline]
130 fn from(t: T) -> SemiSticky<T> {
131 SemiSticky::new(t)
132 }
133}
134
135impl<T: Clone> Clone for SemiSticky<T> {
136 #[inline]
137 fn clone(&self) -> SemiSticky<T> {
138 SemiSticky::new(self.get().clone())
139 }
140}
141
142impl<T: Default> Default for SemiSticky<T> {
143 #[inline]
144 fn default() -> SemiSticky<T> {
145 SemiSticky::new(T::default())
146 }
147}
148
149impl<T: PartialEq> PartialEq for SemiSticky<T> {
150 #[inline]
151 fn eq(&self, other: &SemiSticky<T>) -> bool {
152 *self.get() == *other.get()
153 }
154}
155
156impl<T: Eq> Eq for SemiSticky<T> {}
157
158impl<T: PartialOrd> PartialOrd for SemiSticky<T> {
159 #[inline]
160 fn partial_cmp(&self, other: &SemiSticky<T>) -> Option<cmp::Ordering> {
161 self.get().partial_cmp(&*other.get())
162 }
163
164 #[inline]
165 fn lt(&self, other: &SemiSticky<T>) -> bool {
166 *self.get() < *other.get()
167 }
168
169 #[inline]
170 fn le(&self, other: &SemiSticky<T>) -> bool {
171 *self.get() <= *other.get()
172 }
173
174 #[inline]
175 fn gt(&self, other: &SemiSticky<T>) -> bool {
176 *self.get() > *other.get()
177 }
178
179 #[inline]
180 fn ge(&self, other: &SemiSticky<T>) -> bool {
181 *self.get() >= *other.get()
182 }
183}
184
185impl<T: Ord> Ord for SemiSticky<T> {
186 #[inline]
187 fn cmp(&self, other: &SemiSticky<T>) -> cmp::Ordering {
188 self.get().cmp(&*other.get())
189 }
190}
191
192impl<T: fmt::Display> fmt::Display for SemiSticky<T> {
193 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
194 fmt::Display::fmt(self.get(), f)
195 }
196}
197
198impl<T: fmt::Debug> fmt::Debug for SemiSticky<T> {
199 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
200 match self.try_get() {
201 Ok(value) => f.debug_struct("SemiSticky").field("value", value).finish(),
202 Err(..) => {
203 struct InvalidPlaceholder;
204 impl fmt::Debug for InvalidPlaceholder {
205 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 f.write_str("<invalid thread>")
207 }
208 }
209
210 f.debug_struct("SemiSticky")
211 .field("value", &InvalidPlaceholder)
212 .finish()
213 }
214 }
215 }
216}
217
218#[test]
219fn test_basic() {
220 use std::thread;
221 let val = SemiSticky::new(true);
222 assert_eq!(val.to_string(), "true");
223 assert_eq!(val.get(), &true);
224 assert!(val.try_get().is_ok());
225 thread::spawn(move || {
226 assert!(val.try_get().is_err());
227 })
228 .join()
229 .unwrap();
230}
231
232#[test]
233fn test_mut() {
234 let mut val = SemiSticky::new(true);
235 *val.get_mut() = false;
236 assert_eq!(val.to_string(), "false");
237 assert_eq!(val.get(), &false);
238}
239
240#[test]
241#[should_panic]
242fn test_access_other_thread() {
243 use std::thread;
244 let val = SemiSticky::new(true);
245 thread::spawn(move || {
246 val.get();
247 })
248 .join()
249 .unwrap();
250}
251
252#[test]
253fn test_drop_same_thread() {
254 use std::sync::atomic::{AtomicBool, Ordering};
255 use std::sync::Arc;
256 let was_called = Arc::new(AtomicBool::new(false));
257 struct X(Arc<AtomicBool>);
258 impl Drop for X {
259 fn drop(&mut self) {
260 self.0.store(true, Ordering::SeqCst);
261 }
262 }
263 let val = SemiSticky::new(X(was_called.clone()));
264 mem::drop(val);
265 assert_eq!(was_called.load(Ordering::SeqCst), true);
266}
267
268#[test]
269fn test_noop_drop_elsewhere() {
270 use std::sync::atomic::{AtomicBool, Ordering};
271 use std::sync::Arc;
272 use std::thread;
273
274 let was_called = Arc::new(AtomicBool::new(false));
275
276 {
277 let was_called = was_called.clone();
278 thread::spawn(move || {
279 struct X(Arc<AtomicBool>);
280 impl Drop for X {
281 fn drop(&mut self) {
282 self.0.store(true, Ordering::SeqCst);
283 }
284 }
285
286 let val = SemiSticky::new(X(was_called.clone()));
287 assert!(thread::spawn(move || {
288 val.try_get().ok();
290 })
291 .join()
292 .is_ok());
293
294 assert_eq!(was_called.load(Ordering::SeqCst), false);
295 })
296 .join()
297 .unwrap();
298 }
299
300 assert_eq!(was_called.load(Ordering::SeqCst), true);
301}
302
303#[test]
304fn test_rc_sending() {
305 use std::rc::Rc;
306 use std::thread;
307 let val = SemiSticky::new(Rc::new(true));
308 thread::spawn(move || {
309 assert!(val.try_get().is_err());
310 })
311 .join()
312 .unwrap();
313}