Skip to main content

incular_assets/
lib.rs

1//! Font handles, asset bundles and non-raster resource foundations for
2//! Incular.
3//!
4//! Raster image loading deliberately lives in `incular-image`, which keeps
5//! renderer and widget users from depending on unrelated asset categories.
6
7use std::{fmt, sync::Arc};
8
9mod bundle;
10pub use bundle::{
11    AssetBundle, AssetError, CachingAssetBundle, DirectoryAssetBundle, MemoryAssetBundle,
12};
13
14/// Stable renderer-independent identity for a loaded font asset.
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16pub struct FontId(pub u64);
17
18/// Immutable, cheaply cloned font source bytes. The source may be a heap
19/// allocation or a read-only file mapping owned by system font discovery, so
20/// sharing a handle never copies the font file.
21#[derive(Clone)]
22pub struct FontBytes(Arc<dyn AsRef<[u8]> + Send + Sync>);
23
24impl FontBytes {
25    /// Shares an existing byte source without copying it.
26    #[must_use]
27    pub fn from_shared(source: Arc<dyn AsRef<[u8]> + Send + Sync>) -> Self {
28        Self(source)
29    }
30}
31impl std::ops::Deref for FontBytes {
32    type Target = [u8];
33    fn deref(&self) -> &[u8] {
34        (*self.0).as_ref()
35    }
36}
37impl AsRef<[u8]> for FontBytes {
38    fn as_ref(&self) -> &[u8] {
39        self
40    }
41}
42impl PartialEq for FontBytes {
43    fn eq(&self, other: &Self) -> bool {
44        Arc::ptr_eq(&self.0, &other.0) || **self == **other
45    }
46}
47impl Eq for FontBytes {}
48impl From<Arc<[u8]>> for FontBytes {
49    fn from(bytes: Arc<[u8]>) -> Self {
50        Self(Arc::new(bytes))
51    }
52}
53impl From<Vec<u8>> for FontBytes {
54    fn from(bytes: Vec<u8>) -> Self {
55        Self(Arc::new(bytes))
56    }
57}
58impl From<&'static [u8]> for FontBytes {
59    fn from(bytes: &'static [u8]) -> Self {
60        Self(Arc::new(bytes))
61    }
62}
63impl<const N: usize> From<[u8; N]> for FontBytes {
64    fn from(bytes: [u8; N]) -> Self {
65        Self(Arc::new(bytes))
66    }
67}
68
69/// Font bytes and their stable identity. Paths are deliberately not part of
70/// the public identity: system discovery and bundled assets both produce this
71/// same handle.
72#[derive(Clone, PartialEq, Eq)]
73pub struct FontHandle {
74    id: FontId,
75    bytes: FontBytes,
76    face_index: u32,
77}
78impl FontHandle {
79    #[must_use]
80    pub fn new(id: FontId, bytes: impl Into<FontBytes>) -> Self {
81        Self::with_face_index(id, bytes, 0)
82    }
83    /// Creates a handle for a face in an OpenType collection. The caller owns
84    /// the identity: collection index must be included in `id`.
85    #[must_use]
86    pub fn with_face_index(id: FontId, bytes: impl Into<FontBytes>, face_index: u32) -> Self {
87        Self {
88            id,
89            bytes: bytes.into(),
90            face_index,
91        }
92    }
93    #[must_use]
94    pub const fn id(&self) -> FontId {
95        self.id
96    }
97    #[must_use]
98    pub fn bytes(&self) -> &FontBytes {
99        &self.bytes
100    }
101    #[must_use]
102    pub const fn face_index(&self) -> u32 {
103        self.face_index
104    }
105}
106impl fmt::Debug for FontHandle {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        f.debug_struct("FontHandle")
109            .field("id", &self.id)
110            .field("face_index", &self.face_index)
111            .finish_non_exhaustive()
112    }
113}