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}