1use derive_generic_visitor::{Drive, DriveMut, DriveTwo, Visit, VisitMut, VisitTwo};
2use serde::{Deserialize, Serialize};
3use std::hash::Hash;
4use std::ops::{ControlFlow, Deref};
5use std::sync::Arc;
6
7use crate::common::hash_by_addr::HashByAddr;
8use crate::common::type_map::Mappable;
9
10#[derive(PartialEq, Eq, Hash)]
16pub struct HashConsed<T>(HashByAddr<Arc<T>>);
17
18impl<T> Clone for HashConsed<T> {
19 fn clone(&self) -> Self {
20 Self(self.0.clone())
21 }
22}
23
24impl<T> HashConsed<T> {
25 pub fn inner(&self) -> &T {
26 self.0.0.as_ref()
27 }
28}
29
30impl<T: PartialOrd> PartialOrd for HashConsed<T> {
31 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
32 self.inner().partial_cmp(other.inner())
33 }
34}
35
36impl<T: Ord> Ord for HashConsed<T> {
37 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
38 self.inner().cmp(other.inner())
39 }
40}
41
42pub trait HashConsable: Hash + PartialEq + Eq + Clone + Mappable {}
43impl<T> HashConsable for T where T: Hash + PartialEq + Eq + Clone + Mappable {}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
47pub struct HashConsId(u64);
48
49mod intern_table {
55 use rustc_hash::FxBuildHasher;
56 use std::borrow::Borrow;
57 use std::sync::atomic::{AtomicU64, Ordering};
58 use std::sync::{Arc, LazyLock, RwLock};
59
60 use super::{HashConsId, HashConsable, HashConsed};
61 use crate::common::hash_by_addr::HashByAddr;
62 use crate::common::type_map::{Mappable, Mapper, TypeMap};
63
64 type SeqHashMap<K, V> = indexmap::IndexMap<K, V, FxBuildHasher>;
65
66 fn fresh_id() -> HashConsId {
68 static ID: AtomicU64 = AtomicU64::new(0);
69 HashConsId(ID.fetch_add(1, Ordering::Relaxed))
70 }
71
72 struct InternMapper;
81 impl Mapper for InternMapper {
82 type Value<T: Mappable> = SeqHashMap<Arc<T>, HashConsId>;
83 }
84 static INTERNED: LazyLock<RwLock<TypeMap<InternMapper>>> = LazyLock::new(Default::default);
85
86 pub fn intern<T: HashConsable, U>(inner: U) -> HashConsed<T>
88 where
89 Arc<T>: Borrow<U>,
90 U: Into<Arc<T>> + std::hash::Hash,
91 U: indexmap::Equivalent<Arc<T>>,
92 {
93 let arc = if let read_guard = INTERNED.read().unwrap()
95 && let Some(map) = read_guard.get::<T>()
96 && let Some((arc, _id)) = map.get_key_value(&inner)
97 {
98 arc.clone()
99 } else {
100 let mut write_guard = INTERNED.write().unwrap();
102 let map: &mut SeqHashMap<Arc<T>, _> = write_guard.or_default::<T>();
103 if let Some((arc, _id)) = map.get_key_value(&inner) {
104 arc.clone()
105 } else {
106 let arc: Arc<T> = inner.into();
107 map.insert(arc.clone(), fresh_id());
108 arc
109 }
110 };
111 HashConsed(HashByAddr(arc))
112 }
113
114 pub fn mutate_in_place<T: HashConsable, R, F: FnOnce(&mut T) -> R>(
116 x: &mut HashConsed<T>,
117 f: F,
118 ) -> Result<R, F> {
119 let arc = &mut x.0.0;
120 if Arc::strong_count(arc) != 2 {
124 return Err(f);
125 }
126 {
127 let mut write_guard = INTERNED.write().unwrap();
129 if let Some((other_arc, _)) = write_guard.or_default::<T>().swap_remove_entry(&*arc) {
130 drop(other_arc);
131 } else {
132 return Err(f);
134 }
135 }
138 let ret = match Arc::get_mut(arc) {
140 Some(val) => Ok(f(val)),
141 None => Err(f),
142 };
143 *x = HashConsed::from_arc(arc.clone());
146 ret
147 }
148
149 pub fn id<T: HashConsable>(x: &HashConsed<T>) -> HashConsId {
152 let read_guard = INTERNED.read().unwrap();
155 let map = read_guard.get::<T>().unwrap();
156 let (_arc, id) = map.get_key_value(&x.0.0).unwrap();
157 *id
158 }
159}
160
161impl<T> HashConsed<T>
162where
163 T: HashConsable,
164{
165 pub fn new(inner: T) -> Self {
168 intern_table::intern(inner)
169 }
170 pub fn from_arc(inner: Arc<T>) -> Self {
172 intern_table::intern(inner)
173 }
174
175 pub fn with_inner_mut<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {
177 match intern_table::mutate_in_place(self, f) {
178 Ok(r) => r,
179 Err(f) => {
180 let mut value = self.inner().clone();
182 let ret = f(&mut value);
183 *self = Self::new(value);
185 ret
186 }
187 }
188 }
189
190 pub fn id(&self) -> HashConsId {
191 intern_table::id(self)
192 }
193}
194
195impl<T> Deref for HashConsed<T> {
196 type Target = T;
197 fn deref(&self) -> &Self::Target {
198 self.inner()
199 }
200}
201
202impl<T: std::fmt::Debug> std::fmt::Debug for HashConsed<T> {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 f.debug_tuple("HashConsed").field(self.inner()).finish()
206 }
207}
208
209impl<'s, T, V: Visit<'s, T>> Drive<'s, V> for HashConsed<T> {
210 fn drive_inner(&'s self, v: &mut V) -> ControlFlow<V::Break> {
211 v.visit(self.inner())
212 }
213}
214impl<'s, T, V: VisitTwo<'s, T>> DriveTwo<'s, V> for HashConsed<T> {
215 fn drive_two_inner(&'s self, other: &'s Self, v: &mut V) -> ControlFlow<V::Break> {
216 v.visit(self.inner(), other.inner())
217 }
218}
219impl<'s, T, V> DriveMut<'s, V> for HashConsed<T>
221where
222 T: HashConsable,
223 V: for<'a> VisitMut<'a, T>,
224{
225 fn drive_inner_mut(&'s mut self, v: &mut V) -> ControlFlow<V::Break> {
226 self.with_inner_mut(|inner| v.visit(inner))
227 }
228}
229
230pub use serialize::{HashConsDedupSerializer, HashConsSerializerState};
237mod serialize {
238 use indexmap::IndexMap as SeqHashMap;
239 use serde::{Deserialize, Serialize};
240 use serde_state::{DeserializeState, SerializeState};
241 use std::any::type_name;
242 use std::cell::RefCell;
243 use std::collections::HashSet;
244
245 use super::{HashConsId, HashConsable, HashConsed};
246 use crate::common::type_map::{Mappable, Mapper, TypeMap};
247
248 pub trait HashConsSerializerState: Sized {
249 fn record_serialized<T: Mappable>(&self, id: HashConsId) -> Option<bool>;
252 fn record_deserialized<T: Mappable>(&self, id: HashConsId, value: HashConsed<T>);
254 fn get_deserialized_val<T: Mappable>(&self, id: HashConsId) -> Option<HashConsed<T>>;
256 }
257
258 impl HashConsSerializerState for () {
259 fn record_serialized<T: Mappable>(&self, _id: HashConsId) -> Option<bool> {
260 None
261 }
262 fn record_deserialized<T: Mappable>(&self, _id: HashConsId, _value: HashConsed<T>) {}
263 fn get_deserialized_val<T: Mappable>(&self, _id: HashConsId) -> Option<HashConsed<T>> {
264 None
265 }
266 }
267
268 struct SerializeTableMapper;
269 impl Mapper for SerializeTableMapper {
270 type Value<T: Mappable> = HashSet<HashConsId>;
271 }
272 struct DeserializeTableMapper;
273 impl Mapper for DeserializeTableMapper {
274 type Value<T: Mappable> = SeqHashMap<HashConsId, HashConsed<T>>;
275 }
276 #[derive(Default)]
277 pub struct HashConsDedupSerializer {
278 ser: RefCell<TypeMap<SerializeTableMapper>>,
280 de: RefCell<TypeMap<DeserializeTableMapper>>,
282 }
283 impl HashConsSerializerState for HashConsDedupSerializer {
284 fn record_serialized<T: Mappable>(&self, id: HashConsId) -> Option<bool> {
285 Some(self.ser.borrow_mut().or_default::<T>().insert(id))
286 }
287 fn record_deserialized<T: Mappable>(&self, id: HashConsId, val: HashConsed<T>) {
288 self.de.borrow_mut().or_default::<T>().insert(id, val);
289 }
290 fn get_deserialized_val<T: Mappable>(&self, id: HashConsId) -> Option<HashConsed<T>> {
291 self.de
292 .borrow()
293 .get::<T>()
294 .and_then(|map| map.get(&id))
295 .cloned()
296 }
297 }
298
299 #[derive(Serialize, Deserialize, SerializeState, DeserializeState)]
301 #[serde_state(state_implements = HashConsSerializerState)]
302 enum SerRepr<T> {
303 HashConsedValue(#[serde_state(stateless)] HashConsId, T),
307 #[serde_state(stateless)]
310 Deduplicated(HashConsId),
311 Untagged(T),
313 }
314
315 impl<T> Serialize for HashConsed<T>
316 where
317 T: Serialize + HashConsable,
318 {
319 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
320 where
321 S: serde::Serializer,
322 {
323 SerRepr::Untagged(self.inner()).serialize(serializer)
324 }
325 }
326 impl<T, State> SerializeState<State> for HashConsed<T>
329 where
330 T: SerializeState<State> + HashConsable,
331 State: HashConsSerializerState,
332 {
333 fn serialize_state<S>(&self, state: &State, serializer: S) -> Result<S::Ok, S::Error>
334 where
335 S: serde::Serializer,
336 {
337 let hash_cons_id = self.id();
338 let repr = match state.record_serialized::<T>(hash_cons_id) {
339 Some(true) => SerRepr::HashConsedValue(hash_cons_id, self.inner()),
340 Some(false) => SerRepr::Deduplicated(hash_cons_id),
341 None => SerRepr::Untagged(self.inner()),
342 };
343 repr.serialize_state(state, serializer)
344 }
345 }
346
347 impl<'de, T> Deserialize<'de> for HashConsed<T>
348 where
349 T: Deserialize<'de> + HashConsable,
350 {
351 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
352 where
353 D: serde::Deserializer<'de>,
354 {
355 use serde::de::Error;
356 let repr: SerRepr<T> = SerRepr::deserialize(deserializer)?;
357 match repr {
358 SerRepr::HashConsedValue { .. } | SerRepr::Deduplicated { .. } => {
359 let msg = format!(
360 "trying to deserialize a deduplicated value using serde's `{ty}::deserialize` method. \
361 This won't work, use serde_state's \
362 `{ty}::deserialize_state(&HashConsDedupSerializer::default(), _)` instead",
363 ty = type_name::<T>(),
364 );
365 Err(D::Error::custom(msg))
366 }
367 SerRepr::Untagged(val) => Ok(HashConsed::new(val)),
368 }
369 }
370 }
371 impl<'de, T, State> DeserializeState<'de, State> for HashConsed<T>
372 where
373 T: DeserializeState<'de, State> + HashConsable,
374 State: HashConsSerializerState,
375 {
376 fn deserialize_state<D>(state: &State, deserializer: D) -> Result<Self, D::Error>
377 where
378 D: serde::Deserializer<'de>,
379 {
380 use serde::de::Error;
381 let repr: SerRepr<T> = SerRepr::deserialize_state(state, deserializer)?;
382 Ok(match repr {
383 SerRepr::HashConsedValue(hash_cons_id, value) => {
384 let val = HashConsed::new(value);
385 state.record_deserialized(hash_cons_id, val.clone());
386 val
387 }
388 SerRepr::Deduplicated(hash_cons_id) => {
389 state.get_deserialized_val(hash_cons_id).ok_or_else(|| {
390 let msg = format!(
391 "can't deserialize deduplicated value of type {}; \
392 were you careful with managing the deduplication state?",
393 type_name::<T>()
394 );
395 D::Error::custom(msg)
396 })?
397 }
398 SerRepr::Untagged(val) => HashConsed::new(val),
399 })
400 }
401 }
402}
403
404#[test]
405fn test_hash_cons() {
406 let x = HashConsed::new(42u32);
407 let y = HashConsed::new(42u32);
408 assert_eq!(x, y);
409 let z = serde_json::from_value(serde_json::to_value(x.clone()).unwrap()).unwrap();
411 assert_eq!(x, z);
412}
413
414#[test]
415fn test_hash_cons_concurrent() {
416 use itertools::Itertools;
417 let handles = (0..10)
418 .map(|_| std::thread::spawn(|| std::hint::black_box(HashConsed::new(42u32))))
419 .collect_vec();
420 let values = handles.into_iter().map(|h| h.join().unwrap()).collect_vec();
421 assert!(values.iter().all_equal())
422}
423
424#[test]
425fn test_hash_cons_dedup() {
426 use serde_state::{DeserializeState, SerializeState};
427 type Ty = HashConsed<TyKind>;
428 #[derive(Debug, Clone, PartialEq, Eq, Hash, SerializeState, DeserializeState)]
429 #[serde_state(state = HashConsDedupSerializer)]
430 enum TyKind {
431 Bool,
432 Pair(Ty, Ty),
433 }
434
435 let bool1 = HashConsed::new(TyKind::Bool);
437 let bool2 = HashConsed::new(TyKind::Bool);
438 let pair = HashConsed::new(TyKind::Pair(bool1.clone(), bool2));
439 let triple = HashConsed::new(TyKind::Pair(bool1, pair));
440
441 let state = HashConsDedupSerializer::default();
442 let json_val = triple
443 .serialize_state(&state, serde_json::value::Serializer)
444 .unwrap();
445 let state = HashConsDedupSerializer::default();
446 let round_tripped = Ty::deserialize_state(&state, json_val).unwrap();
447
448 assert_eq!(triple, round_tripped);
449}