use std::rc::Rc;
use cranpose_text::{AnnotatedString, RenderString};
pub fn shared_plain_annotated_string(text: &str) -> Rc<AnnotatedString> {
with_shared_plain_text(text, |shared| Rc::clone(&shared.annotated))
}
pub fn shared_plain_render_string(text: &str) -> std::sync::Arc<RenderString> {
with_shared_plain_text(text, |shared| {
std::sync::Arc::clone(
shared
.render
.get_or_init(|| std::sync::Arc::new(shared.annotated.render_string())),
)
})
}
pub(crate) struct SharedPlainText {
annotated: Rc<AnnotatedString>,
render: std::cell::OnceCell<std::sync::Arc<RenderString>>,
}
impl cranpose_ui_graphics::PooledValue for SharedPlainText {
fn is_held(&self) -> bool {
self.annotated.is_held()
|| self
.render
.get()
.is_some_and(|render| std::sync::Arc::strong_count(render) > 1)
}
}
fn with_shared_plain_text<R>(text: &str, read: impl FnOnce(&SharedPlainText) -> R) -> R {
use std::hash::{Hash, Hasher};
let mut hasher = cranpose_ui_graphics::FxHasher::default();
text.hash(&mut hasher);
crate::thread_state::with(|state| {
state.shared_plain_texts.borrow_mut().with(
hasher.finish(),
|shared| shared.annotated.text == text,
|| SharedPlainText {
annotated: Rc::new(AnnotatedString::new(text.to_owned())),
render: std::cell::OnceCell::new(),
},
read,
)
})
}
#[cfg(test)]
#[path = "tests/shared_plain_text_tests.rs"]
mod tests;