rustc_data_structures/sync/
freeze.rs1use std::cell::UnsafeCell;
2use std::hint;
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::ptr::NonNull;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8use crate::sync::{DynSend, DynSync, ReadGuard, RwLock, WriteGuard};
9
10#[derive(#[automatically_derived]
impl<T: ::core::default::Default> ::core::default::Default for FreezeLock<T> {
#[inline]
fn default() -> FreezeLock<T> {
FreezeLock {
data: ::core::default::Default::default(),
frozen: ::core::default::Default::default(),
lock: ::core::default::Default::default(),
}
}
}Default)]
15pub struct FreezeLock<T> {
16 data: UnsafeCell<T>,
17 frozen: AtomicBool,
18
19 lock: RwLock<()>,
21}
22
23unsafe impl<T: DynSync + DynSend> DynSync for FreezeLock<T> {}
24
25impl<T> FreezeLock<T> {
26 #[inline]
27 pub fn new(value: T) -> Self {
28 Self::with(value, false)
29 }
30
31 #[inline]
32 pub fn frozen(value: T) -> Self {
33 Self::with(value, true)
34 }
35
36 #[inline]
37 pub fn with(value: T, frozen: bool) -> Self {
38 Self {
39 data: UnsafeCell::new(value),
40 frozen: AtomicBool::new(frozen),
41 lock: RwLock::new(()),
42 }
43 }
44
45 #[inline]
47 pub fn clone(&self) -> Self
48 where
49 T: Clone,
50 {
51 let lock = self.read();
52 Self::with(lock.clone(), self.is_frozen())
53 }
54
55 #[inline]
56 pub fn is_frozen(&self) -> bool {
57 self.frozen.load(Ordering::Acquire)
58 }
59
60 #[inline]
62 pub fn get(&self) -> Option<&T> {
63 if self.frozen.load(Ordering::Acquire) {
64 unsafe { Some(&*self.data.get()) }
66 } else {
67 hint::cold_path();
68 None
69 }
70 }
71
72 #[inline]
73 pub fn read(&self) -> FreezeReadGuard<'_, T> {
74 FreezeReadGuard {
75 _lock_guard: if self.frozen.load(Ordering::Acquire) {
76 None
77 } else {
78 Some(self.lock.read())
79 },
80 data: unsafe { NonNull::new_unchecked(self.data.get()) },
81 }
82 }
83
84 #[inline]
85 pub fn borrow(&self) -> FreezeReadGuard<'_, T> {
86 self.read()
87 }
88
89 #[inline]
90 #[track_caller]
91 pub fn write(&self) -> FreezeWriteGuard<'_, T> {
92 self.try_write().expect("data should not be frozen if we're still attempting to mutate it")
93 }
94
95 #[inline]
96 pub fn try_write(&self) -> Option<FreezeWriteGuard<'_, T>> {
97 let _lock_guard = self.lock.write();
98 if self.frozen.load(Ordering::Relaxed) {
100 None
101 } else {
102 Some(FreezeWriteGuard {
103 _lock_guard,
104 data: unsafe { NonNull::new_unchecked(self.data.get()) },
105 frozen: &self.frozen,
106 marker: PhantomData,
107 })
108 }
109 }
110
111 #[inline]
112 pub fn freeze(&self) -> &T {
113 if !self.frozen.load(Ordering::Acquire) {
114 let _lock = self.lock.write();
116 self.frozen.store(true, Ordering::Release);
117 }
118
119 unsafe { &*self.data.get() }
121 }
122}
123
124#[must_use = "if unused the FreezeLock may immediately unlock"]
126pub struct FreezeReadGuard<'a, T: ?Sized> {
127 _lock_guard: Option<ReadGuard<'a, ()>>,
128 data: NonNull<T>,
129}
130
131impl<'a, T: ?Sized + 'a> Deref for FreezeReadGuard<'a, T> {
132 type Target = T;
133 #[inline]
134 fn deref(&self) -> &T {
135 unsafe { &*self.data.as_ptr() }
139 }
140}
141
142impl<'a, T: ?Sized> FreezeReadGuard<'a, T> {
143 #[inline]
144 pub fn map<U: ?Sized>(this: Self, f: impl FnOnce(&T) -> &U) -> FreezeReadGuard<'a, U> {
145 FreezeReadGuard { data: NonNull::from(f(&*this)), _lock_guard: this._lock_guard }
146 }
147}
148
149#[must_use = "if unused the FreezeLock may immediately unlock"]
151pub struct FreezeWriteGuard<'a, T: ?Sized> {
152 _lock_guard: WriteGuard<'a, ()>,
153 frozen: &'a AtomicBool,
154 data: NonNull<T>,
155 marker: PhantomData<&'a mut T>,
156}
157
158impl<'a, T> FreezeWriteGuard<'a, T> {
159 pub fn freeze(self) -> &'a T {
160 self.frozen.store(true, Ordering::Release);
161
162 unsafe { &*self.data.as_ptr() }
164 }
165}
166
167impl<'a, T: ?Sized> FreezeWriteGuard<'a, T> {
168 #[inline]
169 pub fn map<U: ?Sized>(
170 mut this: Self,
171 f: impl FnOnce(&mut T) -> &mut U,
172 ) -> FreezeWriteGuard<'a, U> {
173 FreezeWriteGuard {
174 data: NonNull::from(f(&mut *this)),
175 _lock_guard: this._lock_guard,
176 frozen: this.frozen,
177 marker: PhantomData,
178 }
179 }
180}
181
182impl<'a, T: ?Sized + 'a> Deref for FreezeWriteGuard<'a, T> {
183 type Target = T;
184 #[inline]
185 fn deref(&self) -> &T {
186 unsafe { &*self.data.as_ptr() }
188 }
189}
190
191impl<'a, T: ?Sized + 'a> DerefMut for FreezeWriteGuard<'a, T> {
192 #[inline]
193 fn deref_mut(&mut self) -> &mut T {
194 unsafe { &mut *self.data.as_ptr() }
196 }
197}