Move `egui::util::cache` to `egui::cache`; add `FramePublisher` (#5426)
This moves `egui::util::cache` to `egui::cache` (the old path is
deprecated, but still works).
It also adds the `FramePublisher` helper, which can be used to publish a
value which will be retained for this frame and the next:
``` rs
pub type MyPublisher = egui::cache::FramePublisher<MyKey, MyValue>;
// Publish:
ctx.memory_mut(|mem| {
mem.caches.cache::<MyPublisher>().set(key, value);
});
// Retrieve:
let value: Option<MyValue> = ctx.memory_mut(|mem| {
mem.caches
.cache::<MyPublisher>()
.get(key)
.clone()
})
```
This commit is contained in:
parent
c7224aab26
commit
eac7ba01fa
|
|
@ -0,0 +1,69 @@
|
|||
use super::CacheTrait;
|
||||
|
||||
/// A typemap of many caches, all implemented with [`CacheTrait`].
|
||||
///
|
||||
/// You can access egui's caches via [`crate::Memory::caches`],
|
||||
/// found with [`crate::Context::memory_mut`].
|
||||
///
|
||||
/// ```
|
||||
/// use egui::cache::{CacheStorage, ComputerMut, FrameCache};
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct CharCounter {}
|
||||
/// impl ComputerMut<&str, usize> for CharCounter {
|
||||
/// fn compute(&mut self, s: &str) -> usize {
|
||||
/// s.chars().count()
|
||||
/// }
|
||||
/// }
|
||||
/// type CharCountCache<'a> = FrameCache<usize, CharCounter>;
|
||||
///
|
||||
/// # let mut cache_storage = CacheStorage::default();
|
||||
/// let mut cache = cache_storage.cache::<CharCountCache<'_>>();
|
||||
/// assert_eq!(cache.get("hello"), 5);
|
||||
/// ```
|
||||
#[derive(Default)]
|
||||
pub struct CacheStorage {
|
||||
caches: ahash::HashMap<std::any::TypeId, Box<dyn CacheTrait>>,
|
||||
}
|
||||
|
||||
impl CacheStorage {
|
||||
pub fn cache<Cache: CacheTrait + Default>(&mut self) -> &mut Cache {
|
||||
self.caches
|
||||
.entry(std::any::TypeId::of::<Cache>())
|
||||
.or_insert_with(|| Box::<Cache>::default())
|
||||
.as_any_mut()
|
||||
.downcast_mut::<Cache>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Total number of cached values
|
||||
fn num_values(&self) -> usize {
|
||||
self.caches.values().map(|cache| cache.len()).sum()
|
||||
}
|
||||
|
||||
/// Call once per frame to evict cache.
|
||||
pub fn update(&mut self) {
|
||||
self.caches.retain(|_, cache| {
|
||||
cache.update();
|
||||
cache.len() > 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for CacheStorage {
|
||||
fn clone(&self) -> Self {
|
||||
// We return an empty cache that can be filled in again.
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for CacheStorage {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"FrameCacheStorage[{} caches with {} elements]",
|
||||
self.caches.len(),
|
||||
self.num_values()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/// A cache, storing some value for some length of time.
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
pub trait CacheTrait: 'static + Send + Sync {
|
||||
/// Call once per frame to evict cache.
|
||||
fn update(&mut self);
|
||||
|
||||
/// Number of values currently in the cache.
|
||||
fn len(&self) -> usize;
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
|
||||
}
|
||||
|
|
@ -1,9 +1,4 @@
|
|||
//! Computing the same thing each frame can be expensive,
|
||||
//! so often you want to save the result from the previous frame and reuse it.
|
||||
//!
|
||||
//! Enter [`FrameCache`]: it caches the results of a computation for one frame.
|
||||
//! If it is still used next frame, it is not recomputed.
|
||||
//! If it is not used next frame, it is evicted from the cache to save memory.
|
||||
use super::CacheTrait;
|
||||
|
||||
/// Something that does an expensive computation that we want to cache
|
||||
/// to save us from recomputing it each frame.
|
||||
|
|
@ -74,17 +69,6 @@ impl<Value, Computer> FrameCache<Value, Computer> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
pub trait CacheTrait: 'static + Send + Sync {
|
||||
/// Call once per frame to evict cache.
|
||||
fn update(&mut self);
|
||||
|
||||
/// Number of values currently in the cache.
|
||||
fn len(&self) -> usize;
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl<Value: 'static + Send + Sync, Computer: 'static + Send + Sync> CacheTrait
|
||||
for FrameCache<Value, Computer>
|
||||
{
|
||||
|
|
@ -100,65 +84,3 @@ impl<Value: 'static + Send + Sync, Computer: 'static + Send + Sync> CacheTrait
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// use egui::util::cache::{CacheStorage, ComputerMut, FrameCache};
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct CharCounter {}
|
||||
/// impl ComputerMut<&str, usize> for CharCounter {
|
||||
/// fn compute(&mut self, s: &str) -> usize {
|
||||
/// s.chars().count()
|
||||
/// }
|
||||
/// }
|
||||
/// type CharCountCache<'a> = FrameCache<usize, CharCounter>;
|
||||
///
|
||||
/// # let mut cache_storage = CacheStorage::default();
|
||||
/// let mut cache = cache_storage.cache::<CharCountCache<'_>>();
|
||||
/// assert_eq!(cache.get("hello"), 5);
|
||||
/// ```
|
||||
#[derive(Default)]
|
||||
pub struct CacheStorage {
|
||||
caches: ahash::HashMap<std::any::TypeId, Box<dyn CacheTrait>>,
|
||||
}
|
||||
|
||||
impl CacheStorage {
|
||||
pub fn cache<FrameCache: CacheTrait + Default>(&mut self) -> &mut FrameCache {
|
||||
self.caches
|
||||
.entry(std::any::TypeId::of::<FrameCache>())
|
||||
.or_insert_with(|| Box::<FrameCache>::default())
|
||||
.as_any_mut()
|
||||
.downcast_mut::<FrameCache>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Total number of cached values
|
||||
fn num_values(&self) -> usize {
|
||||
self.caches.values().map(|cache| cache.len()).sum()
|
||||
}
|
||||
|
||||
/// Call once per frame to evict cache.
|
||||
pub fn update(&mut self) {
|
||||
for cache in self.caches.values_mut() {
|
||||
cache.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for CacheStorage {
|
||||
fn clone(&self) -> Self {
|
||||
// We return an empty cache that can be filled in again.
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for CacheStorage {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"FrameCacheStorage[{} caches with {} elements]",
|
||||
self.caches.len(),
|
||||
self.num_values()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
use std::hash::Hash;
|
||||
|
||||
use super::CacheTrait;
|
||||
|
||||
/// Stores a key:value pair for the duration of this frame and the next.
|
||||
pub struct FramePublisher<Key: Eq + Hash, Value> {
|
||||
generation: u32,
|
||||
cache: ahash::HashMap<Key, (u32, Value)>,
|
||||
}
|
||||
|
||||
impl<Key: Eq + Hash, Value> Default for FramePublisher<Key, Value> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Key: Eq + Hash, Value> FramePublisher<Key, Value> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
generation: 0,
|
||||
cache: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Publish the value. It will be available for the duration of this and the next frame.
|
||||
pub fn set(&mut self, key: Key, value: Value) {
|
||||
self.cache.insert(key, (self.generation, value));
|
||||
}
|
||||
|
||||
/// Retrieve a value if it was published this or the previous frame.
|
||||
pub fn get(&self, key: &Key) -> Option<&Value> {
|
||||
self.cache.get(key).map(|(_, value)| value)
|
||||
}
|
||||
|
||||
/// Must be called once per frame to clear the cache.
|
||||
pub fn evict_cache(&mut self) {
|
||||
let current_generation = self.generation;
|
||||
self.cache.retain(|_key, cached| {
|
||||
cached.0 == current_generation // only keep those that were published this frame
|
||||
});
|
||||
self.generation = self.generation.wrapping_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Key, Value> CacheTrait for FramePublisher<Key, Value>
|
||||
where
|
||||
Key: 'static + Eq + Hash + Send + Sync,
|
||||
Value: 'static + Send + Sync,
|
||||
{
|
||||
fn update(&mut self) {
|
||||
self.evict_cache();
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.cache.len()
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
//! Caches for preventing the same value from being recomputed every frame.
|
||||
//!
|
||||
//! Computing the same thing each frame can be expensive,
|
||||
//! so often you want to save the result from the previous frame and reuse it.
|
||||
//!
|
||||
//! Enter [`FrameCache`]: it caches the results of a computation for one frame.
|
||||
//! If it is still used next frame, it is not recomputed.
|
||||
//! If it is not used next frame, it is evicted from the cache to save memory.
|
||||
//!
|
||||
//! You can access egui's caches via [`crate::Memory::caches`],
|
||||
//! found with [`crate::Context::memory_mut`].
|
||||
|
||||
mod cache_storage;
|
||||
mod cache_trait;
|
||||
mod frame_cache;
|
||||
mod frame_publisher;
|
||||
|
||||
pub use cache_storage::CacheStorage;
|
||||
pub use cache_trait::CacheTrait;
|
||||
pub use frame_cache::{ComputerMut, FrameCache};
|
||||
pub use frame_publisher::FramePublisher;
|
||||
|
|
@ -393,6 +393,7 @@
|
|||
#![allow(clippy::manual_range_contains)]
|
||||
|
||||
mod animation_manager;
|
||||
pub mod cache;
|
||||
pub mod containers;
|
||||
mod context;
|
||||
mod data;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ pub struct Memory {
|
|||
/// so as not to lock the UI thread.
|
||||
///
|
||||
/// ```
|
||||
/// use egui::util::cache::{ComputerMut, FrameCache};
|
||||
/// use egui::cache::{ComputerMut, FrameCache};
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct CharCounter {}
|
||||
|
|
@ -72,7 +72,7 @@ pub struct Memory {
|
|||
/// });
|
||||
/// ```
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
pub caches: crate::util::cache::CacheStorage,
|
||||
pub caches: crate::cache::CacheStorage,
|
||||
|
||||
// ------------------------------------------
|
||||
/// new fonts that will be applied at the start of the next frame
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Miscellaneous tools used by the rest of egui.
|
||||
|
||||
pub mod cache;
|
||||
pub(crate) mod fixed_cache;
|
||||
pub mod id_type_map;
|
||||
pub mod undoer;
|
||||
|
|
@ -9,3 +8,7 @@ pub use id_type_map::IdTypeMap;
|
|||
|
||||
pub use epaint::emath::History;
|
||||
pub use epaint::util::{hash, hash_with};
|
||||
|
||||
/// Deprecated alias for [`crate::cache`].
|
||||
#[deprecated = "Use egui::cache instead"]
|
||||
pub use crate::cache;
|
||||
|
|
|
|||
|
|
@ -33,9 +33,7 @@ pub fn highlight(
|
|||
// performing it at a separate thread (ctx, ctx.style()) can be used and when ui is available
|
||||
// (ui.ctx(), ui.style()) can be used
|
||||
|
||||
impl egui::util::cache::ComputerMut<(&egui::FontId, &CodeTheme, &str, &str), LayoutJob>
|
||||
for Highlighter
|
||||
{
|
||||
impl egui::cache::ComputerMut<(&egui::FontId, &CodeTheme, &str, &str), LayoutJob> for Highlighter {
|
||||
fn compute(
|
||||
&mut self,
|
||||
(font_id, theme, code, lang): (&egui::FontId, &CodeTheme, &str, &str),
|
||||
|
|
@ -44,7 +42,7 @@ pub fn highlight(
|
|||
}
|
||||
}
|
||||
|
||||
type HighlightCache = egui::util::cache::FrameCache<LayoutJob, Highlighter>;
|
||||
type HighlightCache = egui::cache::FrameCache<LayoutJob, Highlighter>;
|
||||
|
||||
let font_id = style
|
||||
.override_font_id
|
||||
|
|
|
|||
Loading…
Reference in New Issue