use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use gpui::{App, Global, SharedString};
use gpui_kit_semantics::SemanticRegistry;
const GRACE: u64 = 2;
struct Entry<T> {
seen: u64,
grace: u64,
value: Rc<RefCell<T>>,
}
struct Keyed<T>(RefCell<HashMap<SharedString, Entry<T>>>);
impl<T> Default for Keyed<T> {
fn default() -> Self {
Self(RefCell::new(HashMap::new()))
}
}
impl<T: 'static> Global for Keyed<T> {}
pub(crate) fn slot<T: Default + 'static>(id: &SharedString, cx: &mut App) -> Rc<RefCell<T>> {
slot_retained(id, GRACE, cx)
}
pub(crate) fn slot_retained<T: Default + 'static>(
id: &SharedString,
grace: u64,
cx: &mut App,
) -> Rc<RefCell<T>> {
let frame = frame(cx);
if !cx.has_global::<Keyed<T>>() {
cx.set_global(Keyed::<T>::default());
}
let mut entries = cx.global::<Keyed<T>>().0.borrow_mut();
entries.retain(|_, entry| frame.saturating_sub(entry.seen) < entry.grace);
let entry = entries.entry(id.clone()).or_insert_with(|| Entry {
seen: frame,
grace,
value: Rc::new(RefCell::new(T::default())),
});
entry.seen = frame;
entry.grace = grace;
Rc::clone(&entry.value)
}
pub(crate) fn ids<T: 'static>(cx: &App) -> Vec<SharedString> {
let Some(keyed) = cx.try_global::<Keyed<T>>() else {
return Vec::new();
};
let mut ids: Vec<SharedString> = keyed.0.borrow().keys().cloned().collect();
ids.sort();
ids
}
fn frame(cx: &App) -> u64 {
frame_counter(cx).unwrap_or_default()
}
pub(crate) fn frame_counter(cx: &App) -> Option<u64> {
SemanticRegistry::try_global(cx).map(|registry| registry.generation())
}