|
32 | 32 | use std::collections::HashMap;
|
33 | 33 | use std::hash::{Hash, BuildHasher};
|
34 | 34 | use std::cmp::Ordering;
|
| 35 | +use std::marker::PhantomData; |
35 | 36 | use std::fmt::Debug;
|
36 | 37 | use std::fmt::Formatter;
|
37 | 38 | use std::fmt;
|
@@ -241,6 +242,134 @@ impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S>
|
241 | 242 | }
|
242 | 243 | }
|
243 | 244 |
|
| 245 | +/// A type whose inner value can be written once and then will stay read-only |
| 246 | +// This contains a PhantomData<T> since this type conceptually owns a T outside the Mutex once |
| 247 | +// initialized. This ensures that Once<T> is Sync only if T is. If we did not have PhantomData<T> |
| 248 | +// we could send a &Once<Cell<bool>> to multiple threads and call `get` on it to get access |
| 249 | +// to &Cell<bool> on those threads. |
| 250 | +pub struct Once<T>(Lock<Option<T>>, PhantomData<T>); |
| 251 | + |
| 252 | +impl<T> Once<T> { |
| 253 | + /// Creates an Once value which is uninitialized |
| 254 | + #[inline(always)] |
| 255 | + pub fn new() -> Self { |
| 256 | + Once(Lock::new(None), PhantomData) |
| 257 | + } |
| 258 | + |
| 259 | + /// Consumes the value and returns Some(T) if it was initialized |
| 260 | + #[inline(always)] |
| 261 | + pub fn into_inner(self) -> Option<T> { |
| 262 | + self.0.into_inner() |
| 263 | + } |
| 264 | + |
| 265 | + /// Tries to initialize the inner value to `value`. |
| 266 | + /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it |
| 267 | + /// otherwise if the inner value was already set it returns `value` back to the caller |
| 268 | + #[inline] |
| 269 | + pub fn try_set(&self, value: T) -> Option<T> { |
| 270 | + let mut lock = self.0.lock(); |
| 271 | + if lock.is_some() { |
| 272 | + return Some(value); |
| 273 | + } |
| 274 | + *lock = Some(value); |
| 275 | + None |
| 276 | + } |
| 277 | + |
| 278 | + /// Tries to initialize the inner value to `value`. |
| 279 | + /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it |
| 280 | + /// otherwise if the inner value was already set it asserts that `value` is equal to the inner |
| 281 | + /// value and then returns `value` back to the caller |
| 282 | + #[inline] |
| 283 | + pub fn try_set_same(&self, value: T) -> Option<T> where T: Eq { |
| 284 | + let mut lock = self.0.lock(); |
| 285 | + if let Some(ref inner) = *lock { |
| 286 | + assert!(*inner == value); |
| 287 | + return Some(value); |
| 288 | + } |
| 289 | + *lock = Some(value); |
| 290 | + None |
| 291 | + } |
| 292 | + |
| 293 | + /// Tries to initialize the inner value to `value` and panics if it was already initialized |
| 294 | + #[inline] |
| 295 | + pub fn set(&self, value: T) { |
| 296 | + assert!(self.try_set(value).is_none()); |
| 297 | + } |
| 298 | + |
| 299 | + /// Tries to initialize the inner value by calling the closure while ensuring that no-one else |
| 300 | + /// can access the value in the mean time by holding a lock for the duration of the closure. |
| 301 | + /// If the value was already initialized the closure is not called and `false` is returned, |
| 302 | + /// otherwise if the value from the closure initializes the inner value, `true` is returned |
| 303 | + #[inline] |
| 304 | + pub fn init_locking<F: FnOnce() -> T>(&self, f: F) -> bool { |
| 305 | + let mut lock = self.0.lock(); |
| 306 | + if lock.is_some() { |
| 307 | + return false; |
| 308 | + } |
| 309 | + *lock = Some(f()); |
| 310 | + true |
| 311 | + } |
| 312 | + |
| 313 | + /// Tries to initialize the inner value by calling the closure without ensuring that no-one |
| 314 | + /// else can access it. This mean when this is called from multiple threads, multiple |
| 315 | + /// closures may concurrently be computing a value which the inner value should take. |
| 316 | + /// Only one of these closures are used to actually initialize the value. |
| 317 | + /// If some other closure already set the value, |
| 318 | + /// we return the value our closure computed wrapped in a `Option`. |
| 319 | + /// If our closure set the value, `None` is returned. |
| 320 | + /// If the value is already initialized, the closure is not called and `None` is returned. |
| 321 | + #[inline] |
| 322 | + pub fn init_nonlocking<F: FnOnce() -> T>(&self, f: F) -> Option<T> { |
| 323 | + if self.0.lock().is_some() { |
| 324 | + None |
| 325 | + } else { |
| 326 | + self.try_set(f()) |
| 327 | + } |
| 328 | + } |
| 329 | + |
| 330 | + /// Tries to initialize the inner value by calling the closure without ensuring that no-one |
| 331 | + /// else can access it. This mean when this is called from multiple threads, multiple |
| 332 | + /// closures may concurrently be computing a value which the inner value should take. |
| 333 | + /// Only one of these closures are used to actually initialize the value. |
| 334 | + /// If some other closure already set the value, we assert that it our closure computed |
| 335 | + /// a value equal to the value aready set and then |
| 336 | + /// we return the value our closure computed wrapped in a `Option`. |
| 337 | + /// If our closure set the value, `None` is returned. |
| 338 | + /// If the value is already initialized, the closure is not called and `None` is returned. |
| 339 | + #[inline] |
| 340 | + pub fn init_nonlocking_same<F: FnOnce() -> T>(&self, f: F) -> Option<T> where T: Eq { |
| 341 | + if self.0.lock().is_some() { |
| 342 | + None |
| 343 | + } else { |
| 344 | + self.try_set_same(f()) |
| 345 | + } |
| 346 | + } |
| 347 | + |
| 348 | + /// Tries to get a reference to the inner value, returns `None` if it is not yet initialized |
| 349 | + #[inline(always)] |
| 350 | + pub fn try_get(&self) -> Option<&T> { |
| 351 | + let lock = &*self.0.lock(); |
| 352 | + if let Some(ref inner) = *lock { |
| 353 | + // This is safe since we won't mutate the inner value |
| 354 | + unsafe { Some(&*(inner as *const T)) } |
| 355 | + } else { |
| 356 | + None |
| 357 | + } |
| 358 | + } |
| 359 | + |
| 360 | + /// Gets reference to the inner value, panics if it is not yet initialized |
| 361 | + #[inline(always)] |
| 362 | + pub fn get(&self) -> &T { |
| 363 | + self.try_get().expect("value was not set") |
| 364 | + } |
| 365 | + |
| 366 | + /// Gets reference to the inner value, panics if it is not yet initialized |
| 367 | + #[inline(always)] |
| 368 | + pub fn borrow(&self) -> &T { |
| 369 | + self.get() |
| 370 | + } |
| 371 | +} |
| 372 | + |
244 | 373 | impl<T: Copy + Debug> Debug for LockCell<T> {
|
245 | 374 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
246 | 375 | f.debug_struct("LockCell")
|
|
0 commit comments