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