icon_cache/
file.rs

1//! Load icon caches from a file path in a safe manner
2
3use crate::IconCache;
4use file_lock::FileLock;
5use memmap2::Mmap;
6use std::error::Error;
7use std::ops::Deref;
8use std::os::fd::AsRawFd;
9use std::path::Path;
10
11/// Reexports `file_lock` and `memmap2`, which are used in the [OwnedIconCache] type.
12pub mod reexports {
13    pub use file_lock;
14    pub use memmap2;
15}
16
17/// Provides access to an [IconCache] constructed from a file that is guaranteed not to be modified.
18/// 
19/// `OwnedIconCache` holds a lock on the cache file and creates a memory-mapped region with the file's
20/// contents inside. It does not copy the file contents.
21/// 
22/// To access the icon cache, use [OwnedIconCache::icon_cache]
23#[derive(Debug)]
24pub struct OwnedIconCache {
25    pub lock: FileLock,
26    pub memmap: Mmap,
27}
28
29impl OwnedIconCache {
30    /// Open and lock a file. This call may block waiting to acquire a lock if an exclusive lock
31    /// is already held.
32    ///
33    /// If this behaviour is undesirable, use [open_non_blocking](Self::open_non_blocking) instead.
34    pub fn open(path: impl AsRef<Path>) -> std::io::Result<Self> {
35        Self::create(path, true)
36    }
37
38    /// Open and lock a file, returning an error if an exclusive lock on the file was already held 
39    /// by another process.
40    pub fn open_non_blocking(path: impl AsRef<Path>) -> std::io::Result<Self> {
41        Self::create(path, false)
42    }
43
44    /// Access the icon cache held by this `OwnedIconCache`.
45    ///
46    /// Returns an error if the cache could not be parsed.
47    pub fn icon_cache<'a>(&'a self) -> Result<IconCache<'a>, Box<dyn Error + 'a>> {
48        let bytes = self.memmap.deref();
49        IconCache::new_from_bytes(bytes)
50    }
51
52    fn create(path: impl AsRef<Path>, blocking: bool) -> std::io::Result<Self> {
53        let path = path.as_ref();
54        let options = file_lock::FileOptions::new().write(false); // we explicitly do NOT want to write to the cache!
55
56        let lock = FileLock::lock(path, blocking, options)?;
57
58        Self::from_lock(lock)
59    }
60
61    /// Create a `OwnedIconCache` from a locked file
62    pub fn from_lock(lock: FileLock) -> std::io::Result<Self> {
63        let fd = lock.file.as_raw_fd();
64        // SAFETY: we hold `lock`, which claims that `fd` will not change (unless done by us, which we won't)
65        // throughout the lifetime of the lock
66        let memmap = unsafe { Mmap::map(fd)? };
67
68        Ok(Self { lock, memmap })
69    }
70}