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    /// The description of the font slot.
20    pub description: Option<Arc<DataSource>>,
21}
22
23impl FontSlot {
24    /// Creates a new font slot to load.
25    pub fn new<F: FontLoader + Send + 'static>(f: F) -> Self {
26        Self::new_boxed(Box::new(f))
27    }
28
29    /// Creates a new font slot from a boxed font loader trait object.
30    pub fn new_boxed(f: Box<dyn FontLoader + Send>) -> Self {
31        Self {
32            inner: Arc::new(FontSlotInner::with_context(f)),
33            description: None,
34        }
35    }
36
37    /// Creates a new font slot with a loaded font.
38    pub fn new_loaded(f: Option<Font>) -> Self {
39        Self {
40            inner: Arc::new(FontSlotInner::with_value(f)),
41            description: None,
42        }
43    }
44
45    /// Attaches a description to the font slot and returns a new slot.
46    pub fn with_describe(self, desc: DataSource) -> Self {
47        self.with_describe_arc(Arc::new(desc))
48    }
49
50    /// Attaches a description to the font slot and returns a new slot.
51    pub fn with_describe_arc(self, desc: Arc<DataSource>) -> Self {
52        Self {
53            inner: self.inner,
54            description: Some(desc),
55        }
56    }
57
58    /// Gets or makes the font load result.
59    pub fn get_or_init(&self) -> Option<Font> {
60        let res = self.inner.compute_with_context(|mut c| Ok(c.load()));
61        res.unwrap().clone()
62    }
63
64    /// Gets the reference to the font load result (possibly uninitialized).
65    ///
66    /// Returns `None` if the cell is empty, or being initialized. This
67    /// method never blocks.
68    pub fn get_uninitialized(&self) -> Option<Option<Font>> {
69        self.inner
70            .get_uninitialized()
71            .cloned()
72            .map(|e| e.ok().flatten())
73    }
74}
75
76impl fmt::Debug for FontSlot {
77    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78        f.debug_tuple("FontSlot")
79            .field(&self.get_uninitialized())
80            .finish()
81    }
82}