use std::{
any::Any,
fmt,
sync::{Arc, Mutex},
};
#[derive(Clone, Default, Debug)]
pub struct FontUsage(Arc<Mutex<Vec<FontIdentity>>>);
impl FontUsage {
pub fn record(&self, font: FontIdentity) {
let mut fonts = self.0.lock().unwrap_or_else(|error| error.into_inner());
if !fonts.contains(&font) {
fonts.push(font);
}
}
pub fn fonts(&self) -> Vec<FontIdentity> {
let mut fonts = self
.0
.lock()
.unwrap_or_else(|error| error.into_inner())
.clone();
fonts.sort_by(|left, right| {
(&left.name, left.file_hash).cmp(&(&right.name, right.file_hash))
});
fonts
}
}
#[derive(Clone)]
pub struct FontEnvironment {
value: Arc<dyn Any + Send + Sync>,
identity: u64,
usage: Option<Arc<dyn Fn() -> Vec<FontIdentity> + Send + Sync>>,
}
impl std::panic::RefUnwindSafe for FontEnvironment {}
impl std::panic::UnwindSafe for FontEnvironment {}
impl From<&FontEnvironment> for FontEnvironment {
fn from(value: &FontEnvironment) -> Self {
value.clone()
}
}
impl FontEnvironment {
pub fn new<T: Any + Send + Sync>(value: T, identity: u64) -> Self {
Self {
value: Arc::new(value),
identity,
usage: None,
}
}
pub fn snapshot_id(&self) -> u64 {
self.identity
}
pub fn with_usage(
mut self,
usage: impl Fn() -> Vec<FontIdentity> + Send + Sync + 'static,
) -> Self {
self.usage = Some(Arc::new(usage));
self
}
pub fn used_fonts(&self) -> Vec<FontIdentity> {
self.usage.as_ref().map_or_else(Vec::new, |usage| usage())
}
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.value.downcast_ref()
}
}
impl fmt::Debug for FontEnvironment {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("FontEnvironment")
.field("snapshot", &self.identity)
.finish_non_exhaustive()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FontIdentity {
pub name: Option<String>,
pub file_hash: u64,
}