diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-08-09 11:06:37 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-08-09 11:26:41 +0200 |
| commit | 3932bb2cb93be95d67fc56998423eb9ce047fdfa (patch) | |
| tree | c36bd4df1d2c74f8ae100d2f3bd3a0b232b797f5 /src/loading/fs.rs | |
| parent | 3c92bad9a7cd6b880de197806443ffcce2cac9d8 (diff) | |
New source loading architecture
Diffstat (limited to 'src/loading/fs.rs')
| -rw-r--r-- | src/loading/fs.rs | 112 |
1 files changed, 48 insertions, 64 deletions
diff --git a/src/loading/fs.rs b/src/loading/fs.rs index c3ca332e..9289519c 100644 --- a/src/loading/fs.rs +++ b/src/loading/fs.rs @@ -1,8 +1,6 @@ -use std::cell::{Ref, RefCell}; -use std::collections::HashMap; use std::fs::{self, File}; use std::io; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::rc::Rc; use memmap2::Mmap; @@ -10,9 +8,8 @@ use same_file::Handle; use ttf_parser::{name_id, Face}; use walkdir::WalkDir; -use super::{FileId, Loader}; +use super::{FileHash, Loader}; use crate::font::{FaceInfo, FontStretch, FontStyle, FontVariant, FontWeight}; -use crate::util::PathExt; /// Loads fonts and images from the local file system. /// @@ -20,13 +17,12 @@ use crate::util::PathExt; #[derive(Debug, Default, Clone)] pub struct FsLoader { faces: Vec<FaceInfo>, - paths: RefCell<HashMap<FileId, PathBuf>>, } impl FsLoader { /// Create a new loader without any fonts. pub fn new() -> Self { - Self { faces: vec![], paths: RefCell::default() } + Self { faces: vec![] } } /// Builder-style variant of `search_system`. @@ -52,51 +48,6 @@ impl FsLoader { self.search_system_impl(); } - /// Search for all fonts at a path. - /// - /// If the path is a directory, all contained fonts will be searched for - /// recursively. - pub fn search_path(&mut self, dir: impl AsRef<Path>) { - let walk = WalkDir::new(dir) - .follow_links(true) - .sort_by(|a, b| a.file_name().cmp(b.file_name())) - .into_iter() - .filter_map(|e| e.ok()); - - for entry in walk { - let path = entry.path(); - if let Some(ext) = path.extension().and_then(|s| s.to_str()) { - match ext { - #[rustfmt::skip] - "ttf" | "otf" | "TTF" | "OTF" | - "ttc" | "otc" | "TTC" | "OTC" => { - self.search_file(path).ok(); - } - _ => {} - } - } - } - } - - /// Resolve a file id for a path. - pub fn resolve(&self, path: &Path) -> io::Result<FileId> { - let file = File::open(path)?; - let meta = file.metadata()?; - if meta.is_file() { - let handle = Handle::from_file(file)?; - let id = FileId(fxhash::hash64(&handle)); - self.paths.borrow_mut().insert(id, path.normalize()); - Ok(id) - } else { - Err(io::Error::new(io::ErrorKind::Other, "not a file")) - } - } - - /// Return the path of a resolved file. - pub fn path(&self, id: FileId) -> Ref<Path> { - Ref::map(self.paths.borrow(), |paths| paths[&id].as_path()) - } - #[cfg(all(unix, not(target_os = "macos")))] fn search_system_impl(&mut self) { self.search_path("/usr/share/fonts"); @@ -134,6 +85,32 @@ impl FsLoader { } } + /// Search for all fonts at a path. + /// + /// If the path is a directory, all contained fonts will be searched for + /// recursively. + pub fn search_path(&mut self, dir: impl AsRef<Path>) { + let walk = WalkDir::new(dir) + .follow_links(true) + .sort_by(|a, b| a.file_name().cmp(b.file_name())) + .into_iter() + .filter_map(|e| e.ok()); + + for entry in walk { + let path = entry.path(); + if let Some(ext) = path.extension().and_then(|s| s.to_str()) { + match ext { + #[rustfmt::skip] + "ttf" | "otf" | "TTF" | "OTF" | + "ttc" | "otc" | "TTC" | "OTC" => { + self.search_file(path).ok(); + } + _ => {} + } + } + } + } + /// Index the font faces in the file at the given path. /// /// The file may form a font collection and contain multiple font faces, @@ -180,8 +157,12 @@ impl FsLoader { stretch: FontStretch::from_number(face.width().to_number()), }; - let file = self.resolve(path)?; - self.faces.push(FaceInfo { file, index, family, variant }); + self.faces.push(FaceInfo { + path: path.to_owned(), + index, + family, + variant, + }); Ok(()) } @@ -192,16 +173,19 @@ impl Loader for FsLoader { &self.faces } - fn resolve_from(&self, base: FileId, path: &Path) -> io::Result<FileId> { - let full = self.paths.borrow()[&base] - .parent() - .expect("base is a file") - .join(path); - self.resolve(&full) + fn resolve(&self, path: &Path) -> io::Result<FileHash> { + let file = File::open(path)?; + let meta = file.metadata()?; + if meta.is_file() { + let handle = Handle::from_file(file)?; + Ok(FileHash(fxhash::hash64(&handle))) + } else { + Err(io::Error::new(io::ErrorKind::Other, "not a file")) + } } - fn load_file(&self, id: FileId) -> io::Result<Vec<u8>> { - fs::read(&self.paths.borrow()[&id]) + fn load(&self, path: &Path) -> io::Result<Vec<u8>> { + fs::read(path) } } @@ -211,8 +195,8 @@ mod tests { #[test] fn test_index_font_dir() { - let map = FsLoader::new().with_path("fonts").paths.into_inner(); - let mut paths: Vec<_> = map.into_iter().map(|p| p.1).collect(); + let faces = FsLoader::new().with_path("fonts").faces; + let mut paths: Vec<_> = faces.into_iter().map(|info| info.path).collect(); paths.sort(); assert_eq!(paths, [ |
