tinymist_world/font/
slot.rs

1use core::fmt;
2use std::sync::Arc;
3
4use tinymist_std::QueryRef;
5use typst::text::Font;
6
7use crate::debug_loc::DataSource;
8use crate::font::FontLoader;
9
10type FontSlotInner = QueryRef<Option<Font>, (), Box<dyn FontLoader + Send>>;
11
12/// A font slot holds a reference to a font resource. It can be created from
13/// - either a callback to load the font lazily, using [`Self::new`] or
14///   [`Self::new_boxed`],
15/// - or a loaded font, using [`Self::new_loaded`].
16#[derive(Clone)]
17pub struct FontSlot {
18    inner: Arc<FontSlotInner>,
19    pub description: Option<Arc<DataSource>>,
20}
21
22impl FontSlot {
23    /// Creates a font slot to load.
24    pub fn new<F: FontLoader + Send + 'static>(f: F) -> Self {
25        Self::new_boxed(Box::new(f))
26    }
27
28    /// Creates a font slot from a boxed font loader trait object.
29    pub fn new_boxed(f: Box<dyn FontLoader + Send>) -> Self {
30        Self {
31            inner: Arc::new(FontSlotInner::with_context(f)),
32            description: None,
33        }
34    }
35
36    /// Creates a font slot with a loaded font.
37    pub fn new_loaded(f: Option<Font>) -> Self {
38        Self {
39            inner: Arc::new(FontSlotInner::with_value(f)),
40            description: None,
41        }
42    }
43
44    /// Attaches a description to the font slot.
45    pub fn with_describe(self, desc: DataSource) -> Self {
46        self.with_describe_arc(Arc::new(desc))
47    }
48
49    /// Attaches a description to the font slot.
50    pub fn with_describe_arc(self, desc: Arc<DataSource>) -> Self {
51        Self {
52            inner: self.inner,
53            description: Some(desc),
54        }
55    }
56
57    /// Gets or make the font load result.
58    pub fn get_or_init(&self) -> Option<Font> {
59        let res = self.inner.compute_with_context(|mut c| Ok(c.load()));
60        res.unwrap().clone()
61    }
62
63    /// Gets the reference to the font load result (possible uninitialized).
64    ///
65    /// Returns `None` if the cell is empty, or being initialized. This
66    /// method never blocks.
67    pub fn get_uninitialized(&self) -> Option<Option<Font>> {
68        self.inner
69            .get_uninitialized()
70            .cloned()
71            .map(|e| e.ok().flatten())
72    }
73}
74
75impl fmt::Debug for FontSlot {
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        f.debug_tuple("FontSlot")
78            .field(&self.get_uninitialized())
79            .finish()
80    }
81}