Skip to main content

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