tinymist_world/font/
slot.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use core::fmt;
use std::sync::Arc;

use tinymist_std::QueryRef;
use typst::text::Font;

use crate::debug_loc::DataSource;
use crate::font::FontLoader;

type FontSlotInner = QueryRef<Option<Font>, (), Box<dyn FontLoader + Send>>;

/// A font slot holds a reference to a font resource. It can be created from
/// - either a callback to load the font lazily, using [`Self::new`] or
///   [`Self::new_boxed`],
/// - or a loaded font, using [`Self::new_loaded`].
#[derive(Clone)]
pub struct FontSlot {
    inner: Arc<FontSlotInner>,
    pub description: Option<Arc<DataSource>>,
}

impl FontSlot {
    /// Creates a font slot to load.
    pub fn new<F: FontLoader + Send + 'static>(f: F) -> Self {
        Self::new_boxed(Box::new(f))
    }

    /// Creates a font slot from a boxed font loader trait object.
    pub fn new_boxed(f: Box<dyn FontLoader + Send>) -> Self {
        Self {
            inner: Arc::new(FontSlotInner::with_context(f)),
            description: None,
        }
    }

    /// Creates a font slot with a loaded font.
    pub fn new_loaded(f: Option<Font>) -> Self {
        Self {
            inner: Arc::new(FontSlotInner::with_value(f)),
            description: None,
        }
    }

    /// Attaches a description to the font slot.
    pub fn with_describe(self, desc: DataSource) -> Self {
        self.with_describe_arc(Arc::new(desc))
    }

    /// Attaches a description to the font slot.
    pub fn with_describe_arc(self, desc: Arc<DataSource>) -> Self {
        Self {
            inner: self.inner,
            description: Some(desc),
        }
    }

    /// Gets or make the font load result.
    pub fn get_or_init(&self) -> Option<Font> {
        let res = self.inner.compute_with_context(|mut c| Ok(c.load()));
        res.unwrap().clone()
    }

    /// Gets the reference to the font load result (possible uninitialized).
    ///
    /// Returns `None` if the cell is empty, or being initialized. This
    /// method never blocks.
    pub fn get_uninitialized(&self) -> Option<Option<Font>> {
        self.inner
            .get_uninitialized()
            .cloned()
            .map(|e| e.ok().flatten())
    }
}

impl fmt::Debug for FontSlot {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("FontSlot")
            .field(&self.get_uninitialized())
            .finish()
    }
}