use std::{any::Any, sync::Arc};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct TypeId(u64);
impl TypeId {
#[inline]
pub fn of<T: Any + 'static>() -> Self {
std::any::TypeId::of::<T>().into()
}
#[inline(always)]
pub(crate) fn value(&self) -> u64 {
self.0
}
}
impl From<std::any::TypeId> for TypeId {
#[inline]
fn from(id: std::any::TypeId) -> Self {
Self(epaint::util::hash(id))
}
}
impl nohash_hasher::IsEnabled for TypeId {}
#[cfg(feature = "persistence")]
pub trait SerializableAny:
'static + Any + Clone + serde::Serialize + for<'a> serde::Deserialize<'a> + Send + Sync
{
}
#[cfg(feature = "persistence")]
impl<T> SerializableAny for T where
T: 'static + Any + Clone + serde::Serialize + for<'a> serde::Deserialize<'a> + Send + Sync
{
}
#[cfg(not(feature = "persistence"))]
pub trait SerializableAny: 'static + Any + Clone + for<'a> Send + Sync {}
#[cfg(not(feature = "persistence"))]
impl<T> SerializableAny for T where T: 'static + Any + Clone + for<'a> Send + Sync {}
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug)]
struct SerializedElement {
type_id: TypeId,
ron: Arc<str>,
generation: usize,
}
#[cfg(feature = "persistence")]
type Serializer = fn(&Box<dyn Any + 'static + Send + Sync>) -> Option<String>;
enum Element {
Value {
value: Box<dyn Any + 'static + Send + Sync>,
clone_fn: fn(&Box<dyn Any + 'static + Send + Sync>) -> Box<dyn Any + 'static + Send + Sync>,
#[cfg(feature = "persistence")]
serialize_fn: Option<Serializer>,
},
Serialized(SerializedElement),
}
impl Clone for Element {
fn clone(&self) -> Self {
match &self {
Self::Value {
value,
clone_fn,
#[cfg(feature = "persistence")]
serialize_fn,
} => Self::Value {
value: clone_fn(value),
clone_fn: *clone_fn,
#[cfg(feature = "persistence")]
serialize_fn: *serialize_fn,
},
Self::Serialized(element) => Self::Serialized(element.clone()),
}
}
}
impl std::fmt::Debug for Element {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Self::Value { value, .. } => f
.debug_struct("Element::Value")
.field("type_id", &(**value).type_id())
.finish_non_exhaustive(),
Self::Serialized(SerializedElement {
type_id,
ron,
generation,
}) => f
.debug_struct("Element::Serialized")
.field("type_id", type_id)
.field("ron", ron)
.field("generation", generation)
.finish(),
}
}
}
impl Element {
#[inline]
pub(crate) fn new_temp<T: 'static + Any + Clone + Send + Sync>(t: T) -> Self {
Self::Value {
value: Box::new(t),
clone_fn: |x| {
let x = x.downcast_ref::<T>().unwrap(); Box::new(x.clone())
},
#[cfg(feature = "persistence")]
serialize_fn: None,
}
}
#[inline]
pub(crate) fn new_persisted<T: SerializableAny>(t: T) -> Self {
Self::Value {
value: Box::new(t),
clone_fn: |x| {
let x = x.downcast_ref::<T>().unwrap(); Box::new(x.clone())
},
#[cfg(feature = "persistence")]
serialize_fn: Some(|x| {
let x = x.downcast_ref::<T>().unwrap(); ron::to_string(x).ok()
}),
}
}
#[inline]
pub(crate) fn type_id(&self) -> TypeId {
match self {
Self::Value { value, .. } => (**value).type_id().into(),
Self::Serialized(SerializedElement { type_id, .. }) => *type_id,
}
}
#[inline]
pub(crate) fn get_temp<T: 'static>(&self) -> Option<&T> {
match self {
Self::Value { value, .. } => value.downcast_ref(),
Self::Serialized(_) => None,
}
}
#[inline]
pub(crate) fn get_mut_temp<T: 'static>(&mut self) -> Option<&mut T> {
match self {
Self::Value { value, .. } => value.downcast_mut(),
Self::Serialized(_) => None,
}
}
#[inline]
pub(crate) fn get_temp_mut_or_insert_with<T: 'static + Any + Clone + Send + Sync>(
&mut self,
insert_with: impl FnOnce() -> T,
) -> &mut T {
match self {
Self::Value { value, .. } => {
if !value.is::<T>() {
*self = Self::new_temp(insert_with());
}
}
Self::Serialized(_) => {
*self = Self::new_temp(insert_with());
}
}
match self {
Self::Value { value, .. } => value.downcast_mut().unwrap(), Self::Serialized(_) => unreachable!(),
}
}
#[inline]
pub(crate) fn get_persisted_mut_or_insert_with<T: SerializableAny>(
&mut self,
insert_with: impl FnOnce() -> T,
) -> &mut T {
match self {
Self::Value { value, .. } => {
if !value.is::<T>() {
*self = Self::new_persisted(insert_with());
}
}
#[cfg(feature = "persistence")]
Self::Serialized(SerializedElement { ron, .. }) => {
*self = Self::new_persisted(from_ron_str::<T>(ron).unwrap_or_else(insert_with));
}
#[cfg(not(feature = "persistence"))]
Self::Serialized(_) => {
*self = Self::new_persisted(insert_with());
}
}
match self {
Self::Value { value, .. } => value.downcast_mut().unwrap(), Self::Serialized(_) => unreachable!(),
}
}
pub(crate) fn get_mut_persisted<T: SerializableAny>(&mut self) -> Option<&mut T> {
match self {
Self::Value { value, .. } => value.downcast_mut(),
#[cfg(feature = "persistence")]
Self::Serialized(SerializedElement { ron, .. }) => {
*self = Self::new_persisted(from_ron_str::<T>(ron)?);
match self {
Self::Value { value, .. } => value.downcast_mut(),
Self::Serialized(_) => unreachable!(),
}
}
#[cfg(not(feature = "persistence"))]
Self::Serialized(_) => None,
}
}
#[cfg(feature = "persistence")]
fn to_serialize(&self) -> Option<SerializedElement> {
match self {
Self::Value {
value,
serialize_fn,
..
} => {
if let Some(serialize_fn) = serialize_fn {
let ron = serialize_fn(value)?;
Some(SerializedElement {
type_id: (**value).type_id().into(),
ron: ron.into(),
generation: 1,
})
} else {
None
}
}
Self::Serialized(element) => Some(element.clone()),
}
}
}
#[cfg(feature = "persistence")]
fn from_ron_str<T: serde::de::DeserializeOwned>(ron: &str) -> Option<T> {
match ron::from_str::<T>(ron) {
Ok(value) => Some(value),
Err(_err) => {
#[cfg(feature = "log")]
log::warn!(
"egui: Failed to deserialize {} from memory: {}, ron error: {:?}",
std::any::type_name::<T>(),
_err,
ron
);
None
}
}
}
use crate::Id;
#[derive(Clone, Debug)]
pub struct IdTypeMap {
map: nohash_hasher::IntMap<u64, Element>,
max_bytes_per_type: usize,
}
impl Default for IdTypeMap {
fn default() -> Self {
Self {
map: Default::default(),
max_bytes_per_type: 256 * 1024,
}
}
}
impl IdTypeMap {
#[inline]
pub fn insert_temp<T: 'static + Any + Clone + Send + Sync>(&mut self, id: Id, value: T) {
let hash = hash(TypeId::of::<T>(), id);
self.map.insert(hash, Element::new_temp(value));
}
#[inline]
pub fn insert_persisted<T: SerializableAny>(&mut self, id: Id, value: T) {
let hash = hash(TypeId::of::<T>(), id);
self.map.insert(hash, Element::new_persisted(value));
}
#[inline]
pub fn get_temp<T: 'static + Clone>(&self, id: Id) -> Option<T> {
let hash = hash(TypeId::of::<T>(), id);
self.map.get(&hash).and_then(|x| x.get_temp()).cloned()
}
#[inline]
pub fn get_persisted<T: SerializableAny>(&mut self, id: Id) -> Option<T> {
let hash = hash(TypeId::of::<T>(), id);
self.map
.get_mut(&hash)
.and_then(|x| x.get_mut_persisted())
.cloned()
}
#[inline]
pub fn get_temp_mut_or<T: 'static + Any + Clone + Send + Sync>(
&mut self,
id: Id,
or_insert: T,
) -> &mut T {
self.get_temp_mut_or_insert_with(id, || or_insert)
}
#[inline]
pub fn get_persisted_mut_or<T: SerializableAny>(&mut self, id: Id, or_insert: T) -> &mut T {
self.get_persisted_mut_or_insert_with(id, || or_insert)
}
#[inline]
pub fn get_temp_mut_or_default<T: 'static + Any + Clone + Send + Sync + Default>(
&mut self,
id: Id,
) -> &mut T {
self.get_temp_mut_or_insert_with(id, Default::default)
}
#[inline]
pub fn get_persisted_mut_or_default<T: SerializableAny + Default>(&mut self, id: Id) -> &mut T {
self.get_persisted_mut_or_insert_with(id, Default::default)
}
pub fn get_temp_mut_or_insert_with<T: 'static + Any + Clone + Send + Sync>(
&mut self,
id: Id,
insert_with: impl FnOnce() -> T,
) -> &mut T {
let hash = hash(TypeId::of::<T>(), id);
use std::collections::hash_map::Entry;
match self.map.entry(hash) {
Entry::Vacant(vacant) => vacant
.insert(Element::new_temp(insert_with()))
.get_mut_temp()
.unwrap(), Entry::Occupied(occupied) => {
occupied.into_mut().get_temp_mut_or_insert_with(insert_with)
}
}
}
pub fn get_persisted_mut_or_insert_with<T: SerializableAny>(
&mut self,
id: Id,
insert_with: impl FnOnce() -> T,
) -> &mut T {
let hash = hash(TypeId::of::<T>(), id);
use std::collections::hash_map::Entry;
match self.map.entry(hash) {
Entry::Vacant(vacant) => vacant
.insert(Element::new_persisted(insert_with()))
.get_mut_persisted()
.unwrap(), Entry::Occupied(occupied) => occupied
.into_mut()
.get_persisted_mut_or_insert_with(insert_with),
}
}
#[cfg(feature = "persistence")]
#[allow(unused)]
fn get_generation<T: SerializableAny>(&self, id: Id) -> Option<usize> {
let element = self.map.get(&hash(TypeId::of::<T>(), id))?;
match element {
Element::Value { .. } => Some(0),
Element::Serialized(SerializedElement { generation, .. }) => Some(*generation),
}
}
#[inline]
pub fn remove<T: 'static>(&mut self, id: Id) {
let hash = hash(TypeId::of::<T>(), id);
self.map.remove(&hash);
}
#[inline]
pub fn remove_temp<T: 'static + Default>(&mut self, id: Id) -> Option<T> {
let hash = hash(TypeId::of::<T>(), id);
let mut element = self.map.remove(&hash)?;
Some(std::mem::take(element.get_mut_temp()?))
}
pub fn remove_by_type<T: 'static>(&mut self) {
let key = TypeId::of::<T>();
self.map.retain(|_, e| {
let e: &Element = e;
e.type_id() != key
});
}
#[inline]
pub fn clear(&mut self) {
self.map.clear();
}
#[inline]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.map.len()
}
#[inline]
pub fn count_serialized(&self) -> usize {
self.map
.values()
.filter(|e| matches!(e, Element::Serialized(_)))
.count()
}
pub fn count<T: 'static>(&self) -> usize {
let key = TypeId::of::<T>();
self.map
.iter()
.filter(|(_, e)| {
let e: &Element = e;
e.type_id() == key
})
.count()
}
pub fn max_bytes_per_type(&self) -> usize {
self.max_bytes_per_type
}
pub fn set_max_bytes_per_type(&mut self, max_bytes_per_type: usize) {
self.max_bytes_per_type = max_bytes_per_type;
}
}
#[inline(always)]
fn hash(type_id: TypeId, id: Id) -> u64 {
type_id.value() ^ id.value()
}
#[cfg(feature = "persistence")]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
struct PersistedMap(Vec<(u64, SerializedElement)>);
#[cfg(feature = "persistence")]
impl PersistedMap {
fn from_map(map: &IdTypeMap) -> Self {
profiling::function_scope!();
use std::collections::BTreeMap;
let mut types_map: nohash_hasher::IntMap<TypeId, TypeStats> = Default::default();
#[derive(Default)]
struct TypeStats {
num_bytes: usize,
generations: BTreeMap<usize, GenerationStats>,
}
#[derive(Default)]
struct GenerationStats {
num_bytes: usize,
elements: Vec<(u64, SerializedElement)>,
}
let max_bytes_per_type = map.max_bytes_per_type;
{
profiling::scope!("gather");
for (hash, element) in &map.map {
if let Some(element) = element.to_serialize() {
let stats = types_map.entry(element.type_id).or_default();
stats.num_bytes += element.ron.len();
let generation_stats = stats.generations.entry(element.generation).or_default();
generation_stats.num_bytes += element.ron.len();
generation_stats.elements.push((*hash, element));
} else {
}
}
}
let mut persisted = vec![];
{
profiling::scope!("gc");
for stats in types_map.values() {
let mut bytes_written = 0;
for generation in stats.generations.values() {
if bytes_written == 0
|| bytes_written + generation.num_bytes <= max_bytes_per_type
{
persisted.append(&mut generation.elements.clone());
bytes_written += generation.num_bytes;
} else {
break;
}
}
}
}
Self(persisted)
}
fn into_map(self) -> IdTypeMap {
profiling::function_scope!();
let map = self
.0
.into_iter()
.map(
|(
hash,
SerializedElement {
type_id,
ron,
generation,
},
)| {
(
hash,
Element::Serialized(SerializedElement {
type_id,
ron,
generation: generation + 1, }),
)
},
)
.collect();
IdTypeMap {
map,
..Default::default()
}
}
}
#[cfg(feature = "persistence")]
impl serde::Serialize for IdTypeMap {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
profiling::scope!("IdTypeMap::serialize");
PersistedMap::from_map(self).serialize(serializer)
}
}
#[cfg(feature = "persistence")]
impl<'de> serde::Deserialize<'de> for IdTypeMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
profiling::scope!("IdTypeMap::deserialize");
<PersistedMap>::deserialize(deserializer).map(PersistedMap::into_map)
}
}
#[test]
fn test_two_id_two_type() {
let a = Id::new("a");
let b = Id::new("b");
let mut map: IdTypeMap = Default::default();
map.insert_persisted(a, 13.37);
map.insert_temp(b, 42);
assert_eq!(map.get_persisted::<f64>(a), Some(13.37));
assert_eq!(map.get_persisted::<i32>(b), Some(42));
assert_eq!(map.get_temp::<f64>(a), Some(13.37));
assert_eq!(map.get_temp::<i32>(b), Some(42));
}
#[test]
fn test_two_id_x_two_types() {
#![allow(clippy::approx_constant)]
let a = Id::new("a");
let b = Id::new("b");
let mut map: IdTypeMap = Default::default();
map.insert_persisted(a, 3.14);
map.insert_temp(a, 42);
map.insert_persisted(b, 13.37);
map.insert_temp(b, "Hello World".to_owned());
assert_eq!(map.get_temp::<f64>(a), Some(3.14));
assert_eq!(map.get_temp::<i32>(a), Some(42));
assert_eq!(map.get_temp::<f64>(b), Some(13.37));
assert_eq!(map.get_temp::<String>(b), Some("Hello World".to_owned()));
assert_eq!(map.get_persisted::<f64>(a), Some(3.14));
assert_eq!(map.get_persisted::<i32>(a), Some(42));
assert_eq!(map.get_persisted::<f64>(b), Some(13.37));
assert_eq!(map.get_temp::<String>(b), Some("Hello World".to_owned()));
}
#[test]
fn test_one_id_two_types() {
let id = Id::new("a");
let mut map: IdTypeMap = Default::default();
map.insert_persisted(id, 13.37);
map.insert_temp(id, 42);
assert_eq!(map.get_temp::<f64>(id), Some(13.37));
assert_eq!(map.get_persisted::<f64>(id), Some(13.37));
assert_eq!(map.get_temp::<i32>(id), Some(42));
map.remove::<i32>(id);
assert_eq!(map.get_temp::<i32>(id), None);
assert_eq!(map.get_temp::<f64>(id), Some(13.37));
assert_eq!(map.get_persisted::<f64>(id), Some(13.37));
map.remove::<f64>(id);
assert_eq!(map.get_temp::<f64>(id), None);
assert_eq!(map.get_persisted::<f64>(id), None);
}
#[test]
fn test_mix() {
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, PartialEq)]
struct Foo(i32);
#[derive(Clone, Debug, PartialEq)]
struct Bar(f32);
let id = Id::new("a");
let mut map: IdTypeMap = Default::default();
map.insert_persisted(id, Foo(555));
map.insert_temp(id, Bar(1.0));
assert_eq!(map.get_temp::<Foo>(id), Some(Foo(555)));
assert_eq!(map.get_persisted::<Foo>(id), Some(Foo(555)));
assert_eq!(map.get_temp::<Bar>(id), Some(Bar(1.0)));
map.remove::<Bar>(id);
assert_eq!(map.get_temp::<Bar>(id), None);
assert_eq!(map.get_temp::<Foo>(id), Some(Foo(555)));
assert_eq!(map.get_persisted::<Foo>(id), Some(Foo(555)));
map.remove::<Foo>(id);
assert_eq!(map.get_temp::<Foo>(id), None);
assert_eq!(map.get_persisted::<Foo>(id), None);
}
#[cfg(feature = "persistence")]
#[test]
fn test_mix_serialize() {
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Serializable(i32);
#[derive(Clone, Debug, PartialEq)]
struct NonSerializable(f32);
let id = Id::new("a");
let mut map: IdTypeMap = Default::default();
map.insert_persisted(id, Serializable(555));
map.insert_temp(id, NonSerializable(1.0));
assert_eq!(map.get_temp::<Serializable>(id), Some(Serializable(555)));
assert_eq!(
map.get_persisted::<Serializable>(id),
Some(Serializable(555))
);
assert_eq!(
map.get_temp::<NonSerializable>(id),
Some(NonSerializable(1.0))
);
let serialized = ron::to_string(&map).unwrap();
map.remove::<NonSerializable>(id);
assert_eq!(map.get_temp::<NonSerializable>(id), None);
assert_eq!(map.get_temp::<Serializable>(id), Some(Serializable(555)));
assert_eq!(
map.get_persisted::<Serializable>(id),
Some(Serializable(555))
);
map.remove::<Serializable>(id);
assert_eq!(map.get_temp::<Serializable>(id), None);
assert_eq!(map.get_persisted::<Serializable>(id), None);
let mut map: IdTypeMap = ron::from_str(&serialized).unwrap();
assert_eq!(map.get_temp::<Serializable>(id), None);
assert_eq!(
map.get_persisted::<Serializable>(id),
Some(Serializable(555))
);
assert_eq!(map.get_temp::<Serializable>(id), Some(Serializable(555)));
}
#[cfg(feature = "persistence")]
#[test]
fn test_serialize_generations() {
use serde::{Deserialize, Serialize};
fn serialize_and_deserialize(map: &IdTypeMap) -> IdTypeMap {
let serialized = ron::to_string(map).unwrap();
ron::from_str(&serialized).unwrap()
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct A(i32);
let mut map: IdTypeMap = Default::default();
for i in 0..3 {
map.insert_persisted(Id::new(i), A(i));
}
for i in 0..3 {
assert_eq!(map.get_generation::<A>(Id::new(i)), Some(0));
}
map = serialize_and_deserialize(&map);
for i in 0..3 {
assert_eq!(map.get_generation::<A>(Id::new(i)), Some(2));
}
assert_eq!(map.get_persisted::<A>(Id::new(0)), Some(A(0)));
assert_eq!(map.get_generation::<A>(Id::new(0)), Some(0));
map = serialize_and_deserialize(&map);
assert_eq!(map.get_generation::<A>(Id::new(0)), Some(2));
assert_eq!(map.get_generation::<A>(Id::new(1)), Some(3));
}
#[cfg(feature = "persistence")]
#[test]
fn test_serialize_gc() {
use serde::{Deserialize, Serialize};
fn serialize_and_deserialize(mut map: IdTypeMap, max_bytes_per_type: usize) -> IdTypeMap {
map.set_max_bytes_per_type(max_bytes_per_type);
let serialized = ron::to_string(&map).unwrap();
ron::from_str(&serialized).unwrap()
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct A(usize);
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct B(usize);
let mut map: IdTypeMap = Default::default();
let num_a = 1_000;
let num_b = 10;
for i in 0..num_a {
map.insert_persisted(Id::new(i), A(i));
}
for i in 0..num_b {
map.insert_persisted(Id::new(i), B(i));
}
map = serialize_and_deserialize(map, 100);
assert_eq!(map.count::<A>(), num_a);
assert_eq!(map.count::<B>(), num_b);
map.insert_persisted(Id::new(1_000_000), A(1_000_000));
map.insert_persisted(Id::new(1_000_000), B(1_000_000));
assert_eq!(map.count::<A>(), num_a + 1);
assert_eq!(map.count::<B>(), num_b + 1);
assert_eq!(map.get_persisted::<A>(Id::new(0)), Some(A(0)));
assert_eq!(map.get_persisted::<B>(Id::new(0)), Some(B(0)));
map = serialize_and_deserialize(map, 100);
assert_eq!(
map.count::<A>(),
2,
"We should have dropped the oldest generation, but kept the new value and the read value"
);
assert_eq!(
map.count::<B>(),
num_b + 1,
"B should fit under the byte limit"
);
map.insert_persisted(Id::new(2_000_000), A(2_000_000));
map.insert_persisted(Id::new(2_000_000), B(2_000_000));
map = serialize_and_deserialize(map, 100);
assert_eq!(map.count::<A>(), 3); assert_eq!(map.count::<B>(), num_b + 2); map = serialize_and_deserialize(map, 1);
assert_eq!(map.count::<A>(), 1);
assert_eq!(map.count::<B>(), 1);
assert_eq!(
map.get_persisted::<A>(Id::new(2_000_000)),
Some(A(2_000_000))
);
assert_eq!(
map.get_persisted::<B>(Id::new(2_000_000)),
Some(B(2_000_000))
);
}