egui/util/
id_type_map.rs

1// TODO(emilk): it is possible we can simplify `Element` further by
2// assuming everything is possibly serializable, and by supplying serialize/deserialize functions for them.
3// For non-serializable types, these simply return `None`.
4// This will also allow users to pick their own serialization format per type.
5
6use std::{any::Any, sync::Arc};
7// -----------------------------------------------------------------------------------------------
8
9/// Like [`std::any::TypeId`], but can be serialized and deserialized.
10#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
11#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
12pub struct TypeId(u64);
13
14impl TypeId {
15    #[inline]
16    pub fn of<T: Any + 'static>() -> Self {
17        std::any::TypeId::of::<T>().into()
18    }
19
20    #[inline(always)]
21    pub(crate) fn value(&self) -> u64 {
22        self.0
23    }
24}
25
26impl From<std::any::TypeId> for TypeId {
27    #[inline]
28    fn from(id: std::any::TypeId) -> Self {
29        Self(epaint::util::hash(id))
30    }
31}
32
33impl nohash_hasher::IsEnabled for TypeId {}
34
35// -----------------------------------------------------------------------------------------------
36
37#[cfg(feature = "persistence")]
38pub trait SerializableAny:
39    'static + Any + Clone + serde::Serialize + for<'a> serde::Deserialize<'a> + Send + Sync
40{
41}
42
43#[cfg(feature = "persistence")]
44impl<T> SerializableAny for T where
45    T: 'static + Any + Clone + serde::Serialize + for<'a> serde::Deserialize<'a> + Send + Sync
46{
47}
48
49#[cfg(not(feature = "persistence"))]
50pub trait SerializableAny: 'static + Any + Clone + for<'a> Send + Sync {}
51
52#[cfg(not(feature = "persistence"))]
53impl<T> SerializableAny for T where T: 'static + Any + Clone + for<'a> Send + Sync {}
54
55// -----------------------------------------------------------------------------------------------
56
57#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
58#[derive(Clone, Debug)]
59struct SerializedElement {
60    /// The type of value we are storing.
61    type_id: TypeId,
62
63    /// The ron data we can deserialize.
64    ron: Arc<str>,
65
66    /// Increased by one each time we re-serialize an element that was never deserialized.
67    ///
68    /// Large value = old value that hasn't been read in a while.
69    ///
70    /// Used to garbage collect old values that hasn't been read in a while.
71    generation: usize,
72}
73
74#[cfg(feature = "persistence")]
75type Serializer = fn(&Box<dyn Any + 'static + Send + Sync>) -> Option<String>;
76
77enum Element {
78    /// A value, maybe serializable.
79    Value {
80        /// The actual value.
81        value: Box<dyn Any + 'static + Send + Sync>,
82
83        /// How to clone the value.
84        clone_fn: fn(&Box<dyn Any + 'static + Send + Sync>) -> Box<dyn Any + 'static + Send + Sync>,
85
86        /// How to serialize the value.
87        /// None if non-serializable type.
88        #[cfg(feature = "persistence")]
89        serialize_fn: Option<Serializer>,
90    },
91
92    /// A serialized value
93    Serialized(SerializedElement),
94}
95
96impl Clone for Element {
97    fn clone(&self) -> Self {
98        match &self {
99            Self::Value {
100                value,
101                clone_fn,
102                #[cfg(feature = "persistence")]
103                serialize_fn,
104            } => Self::Value {
105                value: clone_fn(value),
106                clone_fn: *clone_fn,
107                #[cfg(feature = "persistence")]
108                serialize_fn: *serialize_fn,
109            },
110
111            Self::Serialized(element) => Self::Serialized(element.clone()),
112        }
113    }
114}
115
116impl std::fmt::Debug for Element {
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        match &self {
119            Self::Value { value, .. } => f
120                .debug_struct("Element::Value")
121                .field("type_id", &(**value).type_id())
122                .finish_non_exhaustive(),
123            Self::Serialized(SerializedElement {
124                type_id,
125                ron,
126                generation,
127            }) => f
128                .debug_struct("Element::Serialized")
129                .field("type_id", type_id)
130                .field("ron", ron)
131                .field("generation", generation)
132                .finish(),
133        }
134    }
135}
136
137impl Element {
138    /// Create a value that won't be persisted.
139    #[inline]
140    pub(crate) fn new_temp<T: 'static + Any + Clone + Send + Sync>(t: T) -> Self {
141        Self::Value {
142            value: Box::new(t),
143            clone_fn: |x| {
144                // This unwrap will never panic, because we always construct this type using this `new` function and because we return &mut reference only with this type `T`, so type cannot change.
145                #[expect(clippy::unwrap_used)]
146                let x = x.downcast_ref::<T>().unwrap();
147                Box::new(x.clone())
148            },
149            #[cfg(feature = "persistence")]
150            serialize_fn: None,
151        }
152    }
153
154    /// Create a value that will be persisted.
155    #[inline]
156    pub(crate) fn new_persisted<T: SerializableAny>(t: T) -> Self {
157        Self::Value {
158            value: Box::new(t),
159            clone_fn: |x| {
160                // This unwrap will never panic, because we always construct this type using this `new` function and because we return &mut reference only with this type `T`, so type cannot change.
161                #[expect(clippy::unwrap_used)]
162                let x = x.downcast_ref::<T>().unwrap();
163                Box::new(x.clone())
164            },
165            #[cfg(feature = "persistence")]
166            serialize_fn: Some(|x| {
167                // This will never panic too, for same reason.
168                #[expect(clippy::unwrap_used)]
169                let x = x.downcast_ref::<T>().unwrap();
170                ron::to_string(x).ok()
171            }),
172        }
173    }
174
175    /// The type of the stored value.
176    #[inline]
177    pub(crate) fn type_id(&self) -> TypeId {
178        match self {
179            Self::Value { value, .. } => (**value).type_id().into(),
180            Self::Serialized(SerializedElement { type_id, .. }) => *type_id,
181        }
182    }
183
184    pub fn is_temp(&self) -> bool {
185        match self {
186            #[cfg(feature = "persistence")]
187            Self::Value { serialize_fn, .. } => serialize_fn.is_none(),
188
189            #[cfg(not(feature = "persistence"))]
190            Self::Value { .. } => true,
191
192            Self::Serialized(_) => false,
193        }
194    }
195
196    #[inline]
197    pub(crate) fn get_temp<T: 'static>(&self) -> Option<&T> {
198        match self {
199            Self::Value { value, .. } => value.downcast_ref(),
200            Self::Serialized(_) => None,
201        }
202    }
203
204    #[inline]
205    pub(crate) fn get_mut_temp<T: 'static>(&mut self) -> Option<&mut T> {
206        match self {
207            Self::Value { value, .. } => value.downcast_mut(),
208            Self::Serialized(_) => None,
209        }
210    }
211
212    #[inline]
213    pub(crate) fn get_temp_mut_or_insert_with<T: 'static + Any + Clone + Send + Sync>(
214        &mut self,
215        insert_with: impl FnOnce() -> T,
216    ) -> &mut T {
217        match self {
218            Self::Value { value, .. } => {
219                if !value.is::<T>() {
220                    *self = Self::new_temp(insert_with());
221                }
222            }
223            Self::Serialized(_) => {
224                *self = Self::new_temp(insert_with());
225            }
226        }
227
228        match self {
229            // This unwrap will never panic because we already converted object to required type
230            #[expect(clippy::unwrap_used)]
231            Self::Value { value, .. } => value.downcast_mut().unwrap(),
232            Self::Serialized(_) => unreachable!(),
233        }
234    }
235
236    #[inline]
237    pub(crate) fn get_persisted_mut_or_insert_with<T: SerializableAny>(
238        &mut self,
239        insert_with: impl FnOnce() -> T,
240    ) -> &mut T {
241        match self {
242            Self::Value { value, .. } => {
243                if !value.is::<T>() {
244                    *self = Self::new_persisted(insert_with());
245                }
246            }
247
248            #[cfg(feature = "persistence")]
249            Self::Serialized(SerializedElement { ron, .. }) => {
250                *self = Self::new_persisted(from_ron_str::<T>(ron).unwrap_or_else(insert_with));
251            }
252
253            #[cfg(not(feature = "persistence"))]
254            Self::Serialized(_) => {
255                *self = Self::new_persisted(insert_with());
256            }
257        }
258
259        match self {
260            // This unwrap will never panic because we already converted object to required type
261            #[expect(clippy::unwrap_used)]
262            Self::Value { value, .. } => value.downcast_mut().unwrap(),
263            Self::Serialized(_) => unreachable!(),
264        }
265    }
266
267    pub(crate) fn get_mut_persisted<T: SerializableAny>(&mut self) -> Option<&mut T> {
268        match self {
269            Self::Value { value, .. } => value.downcast_mut(),
270
271            #[cfg(feature = "persistence")]
272            Self::Serialized(SerializedElement { ron, .. }) => {
273                *self = Self::new_persisted(from_ron_str::<T>(ron)?);
274
275                match self {
276                    Self::Value { value, .. } => value.downcast_mut(),
277                    Self::Serialized(_) => unreachable!(),
278                }
279            }
280
281            #[cfg(not(feature = "persistence"))]
282            Self::Serialized(_) => None,
283        }
284    }
285
286    #[cfg(feature = "persistence")]
287    fn to_serialize(&self) -> Option<SerializedElement> {
288        match self {
289            Self::Value {
290                value,
291                serialize_fn,
292                ..
293            } => {
294                if let Some(serialize_fn) = serialize_fn {
295                    let ron = serialize_fn(value)?;
296                    Some(SerializedElement {
297                        type_id: (**value).type_id().into(),
298                        ron: ron.into(),
299                        generation: 1,
300                    })
301                } else {
302                    None
303                }
304            }
305            Self::Serialized(element) => Some(element.clone()),
306        }
307    }
308}
309
310#[cfg(feature = "persistence")]
311fn from_ron_str<T: serde::de::DeserializeOwned>(ron: &str) -> Option<T> {
312    match ron::from_str::<T>(ron) {
313        Ok(value) => Some(value),
314        Err(_err) => {
315            log::warn!(
316                "egui: Failed to deserialize {} from memory: {}, ron error: {:?}",
317                std::any::type_name::<T>(),
318                _err,
319                ron
320            );
321            None
322        }
323    }
324}
325
326// -----------------------------------------------------------------------------------------------
327
328use crate::Id;
329
330/// The key used in [`IdTypeMap`], which is a combination of an [`Id`] and a [`TypeId`].
331///
332/// This key can be used to remove or access values in the [`IdTypeMap`] without
333/// knowledge of the `TypeId` `T` that is required for other accessors.
334///
335/// [`RawKey`]s make no guarantees about layout or their ability to be persisted.
336/// They only produce deterministic results if they are used with the map
337/// they were initially obtained from. Using them on other instances of [`IdTypeMap`]
338/// may produce unexpected behavior.
339#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
340#[repr(transparent)]
341pub struct RawKey(u64);
342
343impl nohash_hasher::IsEnabled for RawKey {}
344
345impl RawKey {
346    /// Create a new key for the given type.
347    ///
348    /// Note that two keys with the same id but different types
349    /// will be different keys.
350    ///
351    /// ```
352    /// use egui::{Id, util::id_type_map::RawKey};
353    /// assert_ne!(
354    ///     RawKey::new::<i32>(Id::NULL),
355    ///     RawKey::new::<String>(Id::NULL),
356    /// );
357    /// ```
358    #[inline(always)]
359    pub fn new<T: 'static>(id: Id) -> Self {
360        let type_id = TypeId::of::<T>();
361        Self(type_id.value() ^ id.value())
362    }
363}
364
365// TODO(emilk): make IdTypeMap generic over the key (`Id`), and make a library of IdTypeMap.
366/// Stores values identified by an [`Id`] AND the [`std::any::TypeId`] of the value.
367///
368/// In other words, it maps `(Id, TypeId)` to any value you want.
369///
370/// Values are cloned when read, so keep them small and light.
371/// If you want to store something bigger, wrap them in `Arc<Mutex<…>>`.
372/// Also try `Arc<ArcSwap<…>>`.
373///
374/// Values can either be "persisted" (serializable) or "temporary" (cleared when egui is shut down).
375///
376/// You can store state using the key [`Id::NULL`]. The state will then only be identified by its type.
377///
378/// ```
379/// # use egui::{Id, util::IdTypeMap};
380/// let a = Id::new("a");
381/// let b = Id::new("b");
382/// let mut map: IdTypeMap = Default::default();
383///
384/// // `a` associated with an f64 and an i32
385/// map.insert_persisted(a, 3.14);
386/// map.insert_temp(a, 42);
387///
388/// // `b` associated with an f64 and a `&'static str`
389/// map.insert_persisted(b, 13.37);
390/// map.insert_temp(b, "Hello World".to_owned());
391///
392/// // we can retrieve all four values:
393/// assert_eq!(map.get_temp::<f64>(a), Some(3.14));
394/// assert_eq!(map.get_temp::<i32>(a), Some(42));
395/// assert_eq!(map.get_temp::<f64>(b), Some(13.37));
396/// assert_eq!(map.get_temp::<String>(b), Some("Hello World".to_owned()));
397///
398/// // we can retrieve them like so also:
399/// assert_eq!(map.get_persisted::<f64>(a), Some(3.14));
400/// assert_eq!(map.get_persisted::<i32>(a), Some(42));
401/// assert_eq!(map.get_persisted::<f64>(b), Some(13.37));
402/// assert_eq!(map.get_temp::<String>(b), Some("Hello World".to_owned()));
403/// ```
404#[derive(Clone, Debug)]
405// We use `id XOR typeid` as a key, so we don't need to hash again!
406pub struct IdTypeMap {
407    map: nohash_hasher::IntMap<RawKey, Element>,
408
409    max_bytes_per_type: usize,
410}
411
412impl Default for IdTypeMap {
413    fn default() -> Self {
414        Self {
415            map: Default::default(),
416            max_bytes_per_type: 256 * 1024,
417        }
418    }
419}
420
421impl IdTypeMap {
422    /// Insert a value that will not be persisted.
423    #[inline]
424    pub fn insert_temp<T: 'static + Any + Clone + Send + Sync>(
425        &mut self,
426        id: Id,
427        value: T,
428    ) -> RawKey {
429        let key = RawKey::new::<T>(id);
430        self.map.insert(key, Element::new_temp(value));
431        key
432    }
433
434    /// Insert a value that will be persisted next time you start the app.
435    #[inline]
436    pub fn insert_persisted<T: SerializableAny>(&mut self, id: Id, value: T) {
437        let key = RawKey::new::<T>(id);
438        self.map.insert(key, Element::new_persisted(value));
439        // We don't yet return the key here, because currently all our `raw`
440        // methods are only for temporary values.
441    }
442
443    /// Read a value without trying to deserialize a persisted value.
444    ///
445    /// The call clones the value (if found), so make sure it is cheap to clone!
446    #[inline]
447    pub fn get_temp<T: 'static + Clone>(&self, id: Id) -> Option<T> {
448        let key = RawKey::new::<T>(id);
449        self.map.get(&key).and_then(|x| x.get_temp()).cloned()
450    }
451
452    /// Gets a reference to a value for a given raw key.
453    ///
454    /// Serialized values are ignored.
455    pub fn get_temp_raw(&self, raw: RawKey) -> Option<&(dyn Any + Send + Sync)> {
456        match self.map.get(&raw)? {
457            Element::Value { value, .. } => Some(value.as_ref()),
458            Element::Serialized(_) => None,
459        }
460    }
461
462    /// Gets a mutable reference to a value for a given raw key.
463    ///
464    /// Serialized values are ignored.
465    pub fn get_temp_raw_mut(&mut self, raw: RawKey) -> Option<&mut (dyn Any + Send + Sync)> {
466        match self.map.get_mut(&raw)? {
467            Element::Value { value, .. } => Some(value.as_mut()),
468            Element::Serialized(_) => None,
469        }
470    }
471
472    /// Read a value, optionally deserializing it if available.
473    ///
474    /// NOTE: A mutable `self` is needed because internally this deserializes on first call
475    /// and caches the result (caching requires self-mutability).
476    ///
477    /// The call clones the value (if found), so make sure it is cheap to clone!
478    #[inline]
479    pub fn get_persisted<T: SerializableAny>(&mut self, id: Id) -> Option<T> {
480        let key = RawKey::new::<T>(id);
481        self.map
482            .get_mut(&key)
483            .and_then(|x| x.get_mut_persisted())
484            .cloned()
485    }
486
487    #[inline]
488    pub fn get_temp_mut_or<T: 'static + Any + Clone + Send + Sync>(
489        &mut self,
490        id: Id,
491        or_insert: T,
492    ) -> &mut T {
493        self.get_temp_mut_or_insert_with(id, || or_insert)
494    }
495
496    #[inline]
497    pub fn get_persisted_mut_or<T: SerializableAny>(&mut self, id: Id, or_insert: T) -> &mut T {
498        self.get_persisted_mut_or_insert_with(id, || or_insert)
499    }
500
501    #[inline]
502    pub fn get_temp_mut_or_default<T: 'static + Any + Clone + Send + Sync + Default>(
503        &mut self,
504        id: Id,
505    ) -> &mut T {
506        self.get_temp_mut_or_insert_with(id, Default::default)
507    }
508
509    #[inline]
510    pub fn get_persisted_mut_or_default<T: SerializableAny + Default>(&mut self, id: Id) -> &mut T {
511        self.get_persisted_mut_or_insert_with(id, Default::default)
512    }
513
514    pub fn get_temp_mut_or_insert_with<T: 'static + Any + Clone + Send + Sync>(
515        &mut self,
516        id: Id,
517        insert_with: impl FnOnce() -> T,
518    ) -> &mut T {
519        let key = RawKey::new::<T>(id);
520        use std::collections::hash_map::Entry;
521        match self.map.entry(key) {
522            Entry::Vacant(vacant) => {
523                // this unwrap will never panic, because we insert correct type right now
524                #[expect(clippy::unwrap_used)]
525                vacant
526                    .insert(Element::new_temp(insert_with()))
527                    .get_mut_temp()
528                    .unwrap()
529            }
530            Entry::Occupied(occupied) => {
531                occupied.into_mut().get_temp_mut_or_insert_with(insert_with)
532            }
533        }
534    }
535
536    pub fn get_persisted_mut_or_insert_with<T: SerializableAny>(
537        &mut self,
538        id: Id,
539        insert_with: impl FnOnce() -> T,
540    ) -> &mut T {
541        let key = RawKey::new::<T>(id);
542        use std::collections::hash_map::Entry;
543        match self.map.entry(key) {
544            Entry::Vacant(vacant) => {
545                // this unwrap will never panic, because we insert correct type right now
546                #[expect(clippy::unwrap_used)]
547                vacant
548                    .insert(Element::new_persisted(insert_with()))
549                    .get_mut_persisted()
550                    .unwrap()
551            }
552            Entry::Occupied(occupied) => occupied
553                .into_mut()
554                .get_persisted_mut_or_insert_with(insert_with),
555        }
556    }
557
558    /// For tests
559    #[cfg(feature = "persistence")]
560    #[allow(clippy::allow_attributes, unused)]
561    fn get_generation<T: SerializableAny>(&self, id: Id) -> Option<usize> {
562        let element = self.map.get(&RawKey::new::<T>(id))?;
563        match element {
564            Element::Value { .. } => Some(0),
565            Element::Serialized(SerializedElement { generation, .. }) => Some(*generation),
566        }
567    }
568
569    /// Remove the state of this type and id.
570    #[inline]
571    pub fn remove<T: 'static>(&mut self, id: Id) {
572        let key = RawKey::new::<T>(id);
573        self.map.remove(&key);
574    }
575
576    /// Remove and fetch the state of this type and id.
577    #[inline]
578    pub fn remove_temp<T: 'static + Default>(&mut self, id: Id) -> Option<T> {
579        let key = RawKey::new::<T>(id);
580        let mut element = self.map.remove(&key)?;
581        Some(std::mem::take(element.get_mut_temp()?))
582    }
583
584    /// Remove a temporary value given a raw key.
585    ///
586    /// Serialized values are ignored.
587    pub fn remove_temp_raw(&mut self, raw: RawKey) -> Option<Box<dyn Any + Send + Sync>> {
588        use std::collections::hash_map::Entry;
589        if let Entry::Occupied(e) = self.map.entry(raw)
590            && e.get().is_temp()
591            && let Element::Value { value, .. } = e.remove()
592        {
593            Some(value)
594        } else {
595            None
596        }
597    }
598
599    /// Note all state of the given type.
600    pub fn remove_by_type<T: 'static>(&mut self) {
601        let key = TypeId::of::<T>();
602        self.map.retain(|_, e| {
603            let e: &Element = e;
604            e.type_id() != key
605        });
606    }
607
608    #[inline]
609    pub fn clear(&mut self) {
610        self.map.clear();
611    }
612
613    #[inline]
614    pub fn is_empty(&self) -> bool {
615        self.map.is_empty()
616    }
617
618    #[inline]
619    pub fn len(&self) -> usize {
620        self.map.len()
621    }
622
623    /// Returns all [`RawKey`]s to values in this map.
624    ///
625    /// The returned keys can only be used with this map.
626    ///
627    /// Serializable values will be ignored.
628    pub fn temp_keys(&self) -> impl Iterator<Item = RawKey> {
629        self.map
630            .iter()
631            .filter(|(_, v)| v.is_temp())
632            .map(|(k, _)| *k)
633    }
634
635    /// Count how many values are stored but not yet deserialized.
636    #[inline]
637    pub fn count_serialized(&self) -> usize {
638        self.map
639            .values()
640            .filter(|e| matches!(e, Element::Serialized(_)))
641            .count()
642    }
643
644    /// Count the number of values are stored with the given type.
645    pub fn count<T: 'static>(&self) -> usize {
646        let key = TypeId::of::<T>();
647        self.map
648            .iter()
649            .filter(|(_, e)| {
650                let e: &Element = e;
651                e.type_id() == key
652            })
653            .count()
654    }
655
656    /// The maximum number of bytes that will be used to
657    /// store the persisted state of a single widget type.
658    ///
659    /// Some egui widgets store persisted state that is
660    /// serialized to disk by some backends (e.g. `eframe`).
661    ///
662    /// Example of such widgets is `CollapsingHeader` and `Window`.
663    /// If you keep creating widgets with unique ids (e.g. `Windows` with many different names),
664    /// egui will use up more and more space for these widgets, until this limit is reached.
665    ///
666    /// Once this limit is reached, the state that was read the longest time ago will be dropped first.
667    ///
668    /// This value in itself will not be serialized.
669    pub fn max_bytes_per_type(&self) -> usize {
670        self.max_bytes_per_type
671    }
672
673    /// See [`Self::max_bytes_per_type`].
674    pub fn set_max_bytes_per_type(&mut self, max_bytes_per_type: usize) {
675        self.max_bytes_per_type = max_bytes_per_type;
676    }
677}
678
679// ----------------------------------------------------------------------------
680
681/// How [`IdTypeMap`] is persisted.
682#[cfg(feature = "persistence")]
683#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
684struct PersistedMap(Vec<(u64, SerializedElement)>);
685
686#[cfg(feature = "persistence")]
687impl PersistedMap {
688    fn from_map(map: &IdTypeMap) -> Self {
689        #![expect(clippy::iter_over_hash_type)] // the serialized order doesn't matter
690
691        profiling::function_scope!();
692
693        use std::collections::BTreeMap;
694
695        let mut types_map: nohash_hasher::IntMap<TypeId, TypeStats> = Default::default();
696        #[derive(Default)]
697        struct TypeStats {
698            num_bytes: usize,
699            generations: BTreeMap<usize, GenerationStats>,
700        }
701        #[derive(Default)]
702        struct GenerationStats {
703            num_bytes: usize,
704            elements: Vec<(u64, SerializedElement)>,
705        }
706
707        let max_bytes_per_type = map.max_bytes_per_type;
708
709        {
710            profiling::scope!("gather");
711            for (key, element) in &map.map {
712                if let Some(element) = element.to_serialize() {
713                    let stats = types_map.entry(element.type_id).or_default();
714                    stats.num_bytes += element.ron.len();
715                    let generation_stats = stats.generations.entry(element.generation).or_default();
716                    generation_stats.num_bytes += element.ron.len();
717                    generation_stats.elements.push((key.0, element));
718                } else {
719                    // temporary value that shouldn't be serialized
720                }
721            }
722        }
723
724        let mut persisted = vec![];
725
726        {
727            profiling::scope!("gc");
728            for stats in types_map.values() {
729                let mut bytes_written = 0;
730
731                // Start with the most recently read values, and then go as far as we are allowed.
732                // Always include at least one generation.
733                for generation in stats.generations.values() {
734                    if bytes_written == 0
735                        || bytes_written + generation.num_bytes <= max_bytes_per_type
736                    {
737                        persisted.append(&mut generation.elements.clone());
738                        bytes_written += generation.num_bytes;
739                    } else {
740                        // Omit the rest. The user hasn't read the values in a while.
741                        break;
742                    }
743                }
744            }
745        }
746
747        Self(persisted)
748    }
749
750    fn into_map(self) -> IdTypeMap {
751        profiling::function_scope!();
752        let map = self
753            .0
754            .into_iter()
755            .map(
756                |(
757                    raw,
758                    SerializedElement {
759                        type_id,
760                        ron,
761                        generation,
762                    },
763                )| {
764                    (
765                        RawKey(raw),
766                        Element::Serialized(SerializedElement {
767                            type_id,
768                            ron,
769                            generation: generation + 1, // This is where we increment the generation!
770                        }),
771                    )
772                },
773            )
774            .collect();
775        IdTypeMap {
776            map,
777            ..Default::default()
778        }
779    }
780}
781
782#[cfg(feature = "persistence")]
783impl serde::Serialize for IdTypeMap {
784    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
785    where
786        S: serde::Serializer,
787    {
788        profiling::scope!("IdTypeMap::serialize");
789        PersistedMap::from_map(self).serialize(serializer)
790    }
791}
792
793#[cfg(feature = "persistence")]
794impl<'de> serde::Deserialize<'de> for IdTypeMap {
795    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
796    where
797        D: serde::Deserializer<'de>,
798    {
799        profiling::scope!("IdTypeMap::deserialize");
800        <PersistedMap>::deserialize(deserializer).map(PersistedMap::into_map)
801    }
802}
803
804// ----------------------------------------------------------------------------
805
806#[test]
807fn test_two_id_two_type() {
808    let a = Id::new("a");
809    let b = Id::new("b");
810
811    let mut map: IdTypeMap = Default::default();
812    map.insert_persisted(a, 13.37);
813    map.insert_temp(b, 42);
814    assert_eq!(map.get_persisted::<f64>(a), Some(13.37));
815    assert_eq!(map.get_persisted::<i32>(b), Some(42));
816    assert_eq!(map.get_temp::<f64>(a), Some(13.37));
817    assert_eq!(map.get_temp::<i32>(b), Some(42));
818}
819
820#[test]
821fn test_two_id_x_two_types() {
822    #![expect(clippy::approx_constant)]
823
824    let a = Id::new("a");
825    let b = Id::new("b");
826    let mut map: IdTypeMap = Default::default();
827
828    // `a` associated with an f64 and an i32
829    map.insert_persisted(a, 3.14);
830    map.insert_temp(a, 42);
831
832    // `b` associated with an f64 and a `&'static str`
833    map.insert_persisted(b, 13.37);
834    map.insert_temp(b, "Hello World".to_owned());
835
836    // we can retrieve all four values:
837    assert_eq!(map.get_temp::<f64>(a), Some(3.14));
838    assert_eq!(map.get_temp::<i32>(a), Some(42));
839    assert_eq!(map.get_temp::<f64>(b), Some(13.37));
840    assert_eq!(map.get_temp::<String>(b), Some("Hello World".to_owned()));
841
842    // we can retrieve them like so also:
843    assert_eq!(map.get_persisted::<f64>(a), Some(3.14));
844    assert_eq!(map.get_persisted::<i32>(a), Some(42));
845    assert_eq!(map.get_persisted::<f64>(b), Some(13.37));
846    assert_eq!(map.get_temp::<String>(b), Some("Hello World".to_owned()));
847}
848
849#[test]
850fn test_one_id_two_types() {
851    let id = Id::new("a");
852
853    let mut map: IdTypeMap = Default::default();
854    map.insert_persisted(id, 13.37);
855    map.insert_temp(id, 42);
856
857    assert_eq!(map.get_temp::<f64>(id), Some(13.37));
858    assert_eq!(map.get_persisted::<f64>(id), Some(13.37));
859    assert_eq!(map.get_temp::<i32>(id), Some(42));
860
861    // ------------
862    // Test removal:
863
864    // We can remove:
865    map.remove::<i32>(id);
866    assert_eq!(map.get_temp::<i32>(id), None);
867
868    // Other type is still there, even though it is the same if:
869    assert_eq!(map.get_temp::<f64>(id), Some(13.37));
870    assert_eq!(map.get_persisted::<f64>(id), Some(13.37));
871
872    // But we can still remove the last:
873    map.remove::<f64>(id);
874    assert_eq!(map.get_temp::<f64>(id), None);
875    assert_eq!(map.get_persisted::<f64>(id), None);
876}
877
878#[test]
879fn test_mix() {
880    #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
881    #[derive(Clone, Debug, PartialEq)]
882    struct Foo(i32);
883
884    #[derive(Clone, Debug, PartialEq)]
885    struct Bar(f32);
886
887    let id = Id::new("a");
888
889    let mut map: IdTypeMap = Default::default();
890    map.insert_persisted(id, Foo(555));
891    map.insert_temp(id, Bar(1.0));
892
893    assert_eq!(map.get_temp::<Foo>(id), Some(Foo(555)));
894    assert_eq!(map.get_persisted::<Foo>(id), Some(Foo(555)));
895    assert_eq!(map.get_temp::<Bar>(id), Some(Bar(1.0)));
896
897    // ------------
898    // Test removal:
899
900    // We can remove:
901    map.remove::<Bar>(id);
902    assert_eq!(map.get_temp::<Bar>(id), None);
903
904    // Other type is still there, even though it is the same if:
905    assert_eq!(map.get_temp::<Foo>(id), Some(Foo(555)));
906    assert_eq!(map.get_persisted::<Foo>(id), Some(Foo(555)));
907
908    // But we can still remove the last:
909    map.remove::<Foo>(id);
910    assert_eq!(map.get_temp::<Foo>(id), None);
911    assert_eq!(map.get_persisted::<Foo>(id), None);
912}
913
914#[cfg(feature = "persistence")]
915#[test]
916fn test_mix_serialize() {
917    use serde::{Deserialize, Serialize};
918
919    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
920    struct Serializable(i32);
921
922    #[derive(Clone, Debug, PartialEq)]
923    struct NonSerializable(f32);
924
925    let id = Id::new("a");
926
927    let mut map: IdTypeMap = Default::default();
928    map.insert_persisted(id, Serializable(555));
929    map.insert_temp(id, NonSerializable(1.0));
930
931    assert_eq!(map.get_temp::<Serializable>(id), Some(Serializable(555)));
932    assert_eq!(
933        map.get_persisted::<Serializable>(id),
934        Some(Serializable(555))
935    );
936    assert_eq!(
937        map.get_temp::<NonSerializable>(id),
938        Some(NonSerializable(1.0))
939    );
940
941    // -----------
942
943    let serialized = ron::to_string(&map).unwrap();
944
945    // ------------
946    // Test removal:
947
948    // We can remove:
949    map.remove::<NonSerializable>(id);
950    assert_eq!(map.get_temp::<NonSerializable>(id), None);
951
952    // Other type is still there, even though it is the same if:
953    assert_eq!(map.get_temp::<Serializable>(id), Some(Serializable(555)));
954    assert_eq!(
955        map.get_persisted::<Serializable>(id),
956        Some(Serializable(555))
957    );
958
959    // But we can still remove the last:
960    map.remove::<Serializable>(id);
961    assert_eq!(map.get_temp::<Serializable>(id), None);
962    assert_eq!(map.get_persisted::<Serializable>(id), None);
963
964    // --------------------
965    // Test deserialization:
966
967    let mut map: IdTypeMap = ron::from_str(&serialized).unwrap();
968    assert_eq!(map.get_temp::<Serializable>(id), None);
969    assert_eq!(
970        map.get_persisted::<Serializable>(id),
971        Some(Serializable(555))
972    );
973    assert_eq!(map.get_temp::<Serializable>(id), Some(Serializable(555)));
974}
975
976#[cfg(feature = "persistence")]
977#[test]
978fn test_serialize_generations() {
979    use serde::{Deserialize, Serialize};
980
981    fn serialize_and_deserialize(map: &IdTypeMap) -> IdTypeMap {
982        let serialized = ron::to_string(map).unwrap();
983        ron::from_str(&serialized).unwrap()
984    }
985
986    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
987    struct A(i32);
988
989    let mut map: IdTypeMap = Default::default();
990    for i in 0..3 {
991        map.insert_persisted(Id::new(i), A(i));
992    }
993    for i in 0..3 {
994        assert_eq!(map.get_generation::<A>(Id::new(i)), Some(0));
995    }
996
997    map = serialize_and_deserialize(&map);
998
999    // We use generation 0 for non-serilized,
1000    // 1 for things that have been serialized but never deserialized,
1001    // and then we increment with 1 on each deserialize.
1002    // So we should have generation 2 now:
1003    for i in 0..3 {
1004        assert_eq!(map.get_generation::<A>(Id::new(i)), Some(2));
1005    }
1006
1007    // Reading should reset:
1008    assert_eq!(map.get_persisted::<A>(Id::new(0)), Some(A(0)));
1009    assert_eq!(map.get_generation::<A>(Id::new(0)), Some(0));
1010
1011    // Generations should increment:
1012    map = serialize_and_deserialize(&map);
1013    assert_eq!(map.get_generation::<A>(Id::new(0)), Some(2));
1014    assert_eq!(map.get_generation::<A>(Id::new(1)), Some(3));
1015}
1016
1017#[cfg(feature = "persistence")]
1018#[test]
1019fn test_serialize_gc() {
1020    use serde::{Deserialize, Serialize};
1021
1022    fn serialize_and_deserialize(mut map: IdTypeMap, max_bytes_per_type: usize) -> IdTypeMap {
1023        map.set_max_bytes_per_type(max_bytes_per_type);
1024        let serialized = ron::to_string(&map).unwrap();
1025        ron::from_str(&serialized).unwrap()
1026    }
1027
1028    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1029    struct A(usize);
1030
1031    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1032    struct B(usize);
1033
1034    let mut map: IdTypeMap = Default::default();
1035
1036    let num_a = 1_000;
1037    let num_b = 10;
1038
1039    for i in 0..num_a {
1040        map.insert_persisted(Id::new(i), A(i));
1041    }
1042    for i in 0..num_b {
1043        map.insert_persisted(Id::new(i), B(i));
1044    }
1045
1046    map = serialize_and_deserialize(map, 100);
1047
1048    // We always serialize at least one generation:
1049    assert_eq!(map.count::<A>(), num_a);
1050    assert_eq!(map.count::<B>(), num_b);
1051
1052    // Create a new small generation:
1053    map.insert_persisted(Id::new(1_000_000), A(1_000_000));
1054    map.insert_persisted(Id::new(1_000_000), B(1_000_000));
1055
1056    assert_eq!(map.count::<A>(), num_a + 1);
1057    assert_eq!(map.count::<B>(), num_b + 1);
1058
1059    // And read a value:
1060    assert_eq!(map.get_persisted::<A>(Id::new(0)), Some(A(0)));
1061    assert_eq!(map.get_persisted::<B>(Id::new(0)), Some(B(0)));
1062
1063    map = serialize_and_deserialize(map, 100);
1064
1065    assert_eq!(
1066        map.count::<A>(),
1067        2,
1068        "We should have dropped the oldest generation, but kept the new value and the read value"
1069    );
1070    assert_eq!(
1071        map.count::<B>(),
1072        num_b + 1,
1073        "B should fit under the byte limit"
1074    );
1075
1076    // Create another small generation:
1077    map.insert_persisted(Id::new(2_000_000), A(2_000_000));
1078    map.insert_persisted(Id::new(2_000_000), B(2_000_000));
1079
1080    map = serialize_and_deserialize(map, 100);
1081
1082    assert_eq!(map.count::<A>(), 3); // The read value, plus the two new ones
1083    assert_eq!(map.count::<B>(), num_b + 2); // all the old ones, plus two new ones
1084
1085    // Lower the limit, and we should only have the latest generation:
1086
1087    map = serialize_and_deserialize(map, 1);
1088
1089    assert_eq!(map.count::<A>(), 1);
1090    assert_eq!(map.count::<B>(), 1);
1091
1092    assert_eq!(
1093        map.get_persisted::<A>(Id::new(2_000_000)),
1094        Some(A(2_000_000))
1095    );
1096    assert_eq!(
1097        map.get_persisted::<B>(Id::new(2_000_000)),
1098        Some(B(2_000_000))
1099    );
1100}