1use std::{
2 fmt::Debug,
3 mem::take,
4 ops::{Deref, DerefMut},
5};
6
7use auto_hash_map::AutoSet;
8use bincode::{Decode, Encode};
9use parking_lot::{Mutex, MutexGuard};
10use tracing::trace_span;
11
12use crate::{
13 Invalidator, OperationValue, SerializationInvalidator, get_invalidator,
14 get_serialization_invalidator, manager::with_turbo_tasks,
15};
16
17#[derive(Encode, Decode)]
18struct StateInner<T> {
19 value: T,
20 invalidators: AutoSet<Invalidator>,
21}
22
23impl<T> StateInner<T> {
24 pub fn new(value: T) -> Self {
25 Self {
26 value,
27 invalidators: AutoSet::new(),
28 }
29 }
30
31 pub fn add_invalidator(&mut self, invalidator: Invalidator) {
32 self.invalidators.insert(invalidator);
33 }
34
35 #[must_use]
39 fn set_unconditionally(&mut self, value: T) -> AutoSet<Invalidator> {
40 self.value = value;
41 take(&mut self.invalidators)
42 }
43
44 #[must_use]
47 fn update_conditionally(
48 &mut self,
49 update: impl FnOnce(&mut T) -> bool,
50 ) -> Option<AutoSet<Invalidator>> {
51 if !update(&mut self.value) {
52 return None;
53 }
54 Some(take(&mut self.invalidators))
55 }
56}
57
58impl<T: PartialEq> StateInner<T> {
59 #[must_use]
62 fn set(&mut self, value: T) -> Option<AutoSet<Invalidator>> {
63 if self.value == value {
64 return None;
65 }
66 self.value = value;
67 Some(take(&mut self.invalidators))
68 }
69}
70
71fn notify_mutated(
79 invalidators: AutoSet<Invalidator>,
80 serialization_invalidator: Option<&SerializationInvalidator>,
81) {
82 if invalidators.is_empty() && serialization_invalidator.is_none() {
83 return;
84 }
85 let _span = trace_span!("state value changed").entered();
86 with_turbo_tasks(|tt| {
87 Invalidator::invalidate_all(invalidators, &**tt);
88 if let Some(serialization_invalidator) = serialization_invalidator {
89 tt.invalidate_serialization(serialization_invalidator.task());
90 }
91 });
92}
93
94pub struct StateRef<'a, T> {
95 serialization_invalidator: Option<&'a SerializationInvalidator>,
96 inner: Option<MutexGuard<'a, StateInner<T>>>,
100 mutated: bool,
101}
102
103impl<'a, T> StateRef<'a, T> {
104 fn new(
105 inner: MutexGuard<'a, StateInner<T>>,
106 serialization_invalidator: Option<&'a SerializationInvalidator>,
107 ) -> Self {
108 Self {
109 serialization_invalidator,
110 inner: Some(inner),
111 mutated: false,
112 }
113 }
114
115 fn inner(&self) -> &StateInner<T> {
116 self.inner.as_deref().expect("inner only None during Drop")
117 }
118
119 fn inner_mut(&mut self) -> &mut StateInner<T> {
120 self.inner
121 .as_deref_mut()
122 .expect("inner only None during Drop")
123 }
124}
125
126impl<T> Deref for StateRef<'_, T> {
127 type Target = T;
128
129 fn deref(&self) -> &Self::Target {
130 &self.inner().value
131 }
132}
133
134impl<T> DerefMut for StateRef<'_, T> {
135 fn deref_mut(&mut self) -> &mut Self::Target {
136 self.mutated = true;
137 &mut self.inner_mut().value
138 }
139}
140
141impl<T> Drop for StateRef<'_, T> {
142 fn drop(&mut self) {
143 if !self.mutated {
144 return;
145 }
146 let mut guard = self.inner.take().expect("Drop only called once");
152 let invalidators = take(&mut guard.invalidators);
153 drop(guard);
154 notify_mutated(invalidators, self.serialization_invalidator);
155 }
156}
157
158pub mod parking_lot_mutex_bincode {
159 use bincode::{
160 BorrowDecode,
161 de::{BorrowDecoder, Decoder},
162 enc::Encoder,
163 error::{DecodeError, EncodeError},
164 };
165
166 use super::*;
167
168 pub fn encode<T: Encode, E: Encoder>(
169 mutex: &Mutex<T>,
170 encoder: &mut E,
171 ) -> Result<(), EncodeError> {
172 mutex.lock().encode(encoder)
173 }
174
175 pub fn decode<Context, T: Decode<Context>, D: Decoder<Context = Context>>(
176 decoder: &mut D,
177 ) -> Result<Mutex<T>, DecodeError> {
178 Ok(Mutex::new(T::decode(decoder)?))
179 }
180
181 pub fn borrow_decode<
182 'de,
183 Context,
184 T: BorrowDecode<'de, Context>,
185 D: BorrowDecoder<'de, Context = Context>,
186 >(
187 decoder: &mut D,
188 ) -> Result<Mutex<T>, DecodeError> {
189 Ok(Mutex::new(T::borrow_decode(decoder)?))
190 }
191}
192
193#[derive(Encode, Decode)]
217pub struct State<T> {
218 serialization_invalidator: SerializationInvalidator,
219 #[bincode(with = "parking_lot_mutex_bincode")]
220 inner: Mutex<StateInner<T>>,
221}
222
223impl<T: Debug> Debug for State<T> {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 f.debug_struct("State")
226 .field("value", &self.inner.lock().value)
227 .finish()
228 }
229}
230
231impl<T: Default + OperationValue> Default for State<T> {
232 fn default() -> Self {
233 Self::new(Default::default())
235 }
236}
237
238impl<T> PartialEq for State<T> {
239 fn eq(&self, _other: &Self) -> bool {
240 false
241 }
242}
243impl<T> Eq for State<T> {}
244
245impl<T> State<T> {
246 pub fn new(value: T) -> Self
247 where
248 T: OperationValue,
249 {
250 Self {
251 serialization_invalidator: get_serialization_invalidator(),
252 inner: Mutex::new(StateInner::new(value)),
253 }
254 }
255
256 pub fn get(&self) -> StateRef<'_, T> {
260 let invalidator = get_invalidator();
261 let mut inner = self.inner.lock();
262 if let Some(invalidator) = invalidator {
263 inner.add_invalidator(invalidator);
264 }
265 StateRef::new(inner, Some(&self.serialization_invalidator))
266 }
267
268 pub fn get_untracked(&self) -> StateRef<'_, T> {
270 let inner = self.inner.lock();
271 StateRef::new(inner, Some(&self.serialization_invalidator))
272 }
273
274 pub fn set_unconditionally(&self, value: T) {
277 let invalidators = {
278 let mut inner = self.inner.lock();
279 inner.set_unconditionally(value)
280 };
281 notify_mutated(invalidators, Some(&self.serialization_invalidator));
282 }
283
284 pub fn update_conditionally(&self, update: impl FnOnce(&mut T) -> bool) {
289 let Some(invalidators) = ({
290 let mut inner = self.inner.lock();
291 inner.update_conditionally(update)
292 }) else {
293 return;
294 };
295 notify_mutated(invalidators, Some(&self.serialization_invalidator));
296 }
297}
298
299impl<T: PartialEq> State<T> {
300 pub fn set(&self, value: T) {
303 let Some(invalidators) = ({
304 let mut inner = self.inner.lock();
305 inner.set(value)
306 }) else {
307 return;
308 };
309 notify_mutated(invalidators, Some(&self.serialization_invalidator));
310 }
311}