rustc_data_structures/sync/
freeze.rs
1use std::cell::UnsafeCell;
2use std::intrinsics::likely;
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(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 likely(self.frozen.load(Ordering::Acquire)) {
64 unsafe { Some(&*self.data.get()) }
66 } else {
67 None
68 }
69 }
70
71 #[inline]
72 pub fn read(&self) -> FreezeReadGuard<'_, T> {
73 FreezeReadGuard {
74 _lock_guard: if self.frozen.load(Ordering::Acquire) {
75 None
76 } else {
77 Some(self.lock.read())
78 },
79 data: unsafe { NonNull::new_unchecked(self.data.get()) },
80 }
81 }
82
83 #[inline]
84 pub fn borrow(&self) -> FreezeReadGuard<'_, T> {
85 self.read()
86 }
87
88 #[inline]
89 #[track_caller]
90 pub fn write(&self) -> FreezeWriteGuard<'_, T> {
91 self.try_write().expect("still mutable")
92 }
93
94 #[inline]
95 pub fn try_write(&self) -> Option<FreezeWriteGuard<'_, T>> {
96 let _lock_guard = self.lock.write();
97 if self.frozen.load(Ordering::Relaxed) {
99 None
100 } else {
101 Some(FreezeWriteGuard {
102 _lock_guard,
103 data: unsafe { NonNull::new_unchecked(self.data.get()) },
104 frozen: &self.frozen,
105 marker: PhantomData,
106 })
107 }
108 }
109
110 #[inline]
111 pub fn freeze(&self) -> &T {
112 if !self.frozen.load(Ordering::Acquire) {
113 let _lock = self.lock.write();
115 self.frozen.store(true, Ordering::Release);
116 }
117
118 unsafe { &*self.data.get() }
120 }
121}
122
123#[must_use = "if unused the FreezeLock may immediately unlock"]
125pub struct FreezeReadGuard<'a, T: ?Sized> {
126 _lock_guard: Option<ReadGuard<'a, ()>>,
127 data: NonNull<T>,
128}
129
130impl<'a, T: ?Sized + 'a> Deref for FreezeReadGuard<'a, T> {
131 type Target = T;
132 #[inline]
133 fn deref(&self) -> &T {
134 unsafe { &*self.data.as_ptr() }
138 }
139}
140
141impl<'a, T: ?Sized> FreezeReadGuard<'a, T> {
142 #[inline]
143 pub fn map<U: ?Sized>(this: Self, f: impl FnOnce(&T) -> &U) -> FreezeReadGuard<'a, U> {
144 FreezeReadGuard { data: NonNull::from(f(&*this)), _lock_guard: this._lock_guard }
145 }
146}
147
148#[must_use = "if unused the FreezeLock may immediately unlock"]
150pub struct FreezeWriteGuard<'a, T: ?Sized> {
151 _lock_guard: WriteGuard<'a, ()>,
152 frozen: &'a AtomicBool,
153 data: NonNull<T>,
154 marker: PhantomData<&'a mut T>,
155}
156
157impl<'a, T> FreezeWriteGuard<'a, T> {
158 pub fn freeze(self) -> &'a T {
159 self.frozen.store(true, Ordering::Release);
160
161 unsafe { &*self.data.as_ptr() }
163 }
164}
165
166impl<'a, T: ?Sized> FreezeWriteGuard<'a, T> {
167 #[inline]
168 pub fn map<U: ?Sized>(
169 mut this: Self,
170 f: impl FnOnce(&mut T) -> &mut U,
171 ) -> FreezeWriteGuard<'a, U> {
172 FreezeWriteGuard {
173 data: NonNull::from(f(&mut *this)),
174 _lock_guard: this._lock_guard,
175 frozen: this.frozen,
176 marker: PhantomData,
177 }
178 }
179}
180
181impl<'a, T: ?Sized + 'a> Deref for FreezeWriteGuard<'a, T> {
182 type Target = T;
183 #[inline]
184 fn deref(&self) -> &T {
185 unsafe { &*self.data.as_ptr() }
187 }
188}
189
190impl<'a, T: ?Sized + 'a> DerefMut for FreezeWriteGuard<'a, T> {
191 #[inline]
192 fn deref_mut(&mut self) -> &mut T {
193 unsafe { &mut *self.data.as_ptr() }
195 }
196}