font_index/
shared_data.rs

1//! Shared font data.
2
3use std::{io, fmt};
4use std::path::Path;
5use std::sync::{Arc, Weak};
6use std::time::SystemTime;
7
8enum Inner {
9    Mapped(memmap2::Mmap),
10    Memory(Vec<u8>),
11}
12
13impl Inner {
14    fn data(&self) -> &[u8] {
15        match self {
16            Self::Mapped(mmap) => &*mmap,
17            Self::Memory(vec) => &vec,
18        }
19    }
20}
21
22impl fmt::Debug for Inner {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        match self {
25            Self::Mapped(mmap) => write!(f, "{:?}", mmap),
26            Self::Memory(vec) => write!(f, "{:?}..", &vec[..50]),
27        }
28    }
29}
30
31/// Atomically reference counted, heap allocated or memory mapped buffer.
32#[derive(Clone, Debug)]
33#[repr(transparent)]
34pub struct SharedData {
35    inner: Arc<Inner>,
36}
37
38/// Weak reference to shared data.
39#[derive(Clone, Debug)]
40#[repr(transparent)]
41pub struct WeakSharedData {
42    inner: Weak<Inner>,
43}
44
45impl WeakSharedData {
46    /// Upgrades the weak reference.
47    pub fn upgrade(&self) -> Option<SharedData> {
48        Some(SharedData {
49            inner: self.inner.upgrade()?,
50        })
51    }
52}
53
54impl SharedData {
55    /// Creates shared data from the specified bytes.
56    pub fn new(data: Vec<u8>) -> Self {
57        Self {
58            inner: Arc::new(Inner::Memory(data)),
59        }
60    }
61
62    /// Creates shared data from the specified path.
63    pub fn from_file(
64        path: impl AsRef<Path>,
65        mmap: bool,
66        timestamp: Option<SystemTime>,
67    ) -> Result<Self, io::Error> {
68        let path = path.as_ref();
69        if let Some(timestamp) = timestamp {
70            let metadata = path.metadata()?;
71            let current_timestamp = metadata.modified()?;
72            if timestamp != current_timestamp {
73                // Close enough
74                return Err(io::Error::from(io::ErrorKind::InvalidData));
75            }
76        }
77        let inner = Arc::new(if mmap {
78            let file = std::fs::File::open(path)?;
79            let map = unsafe { memmap2::Mmap::map(&file)? };
80            Inner::Mapped(map)
81        } else {
82            let data = std::fs::read(path)?;
83            Inner::Memory(data)
84        });
85        Ok(Self { inner })
86    }
87
88    /// Creates a new weak reference to the data.
89    pub fn downgrade(&self) -> WeakSharedData {
90        WeakSharedData {
91            inner: Arc::downgrade(&self.inner),
92        }
93    }
94
95    /// Returns the underlying bytes of the data.
96    pub fn as_bytes(&self) -> &[u8] {
97        self.inner.data()
98    }
99
100    /// Returns the number of strong references to the data.
101    pub fn strong_count(&self) -> usize {
102        Arc::strong_count(&self.inner)
103    }
104}
105
106impl std::ops::Deref for SharedData {
107    type Target = [u8];
108
109    fn deref(&self) -> &Self::Target {
110        self.inner.data()
111    }
112}
113
114impl AsRef<[u8]> for SharedData {
115    fn as_ref(&self) -> &[u8] {
116        self.inner.data()
117    }
118}