Skip to main content

scan_fonts/
iterator.rs

1use crate::font;
2use failure::Error;
3use std::convert::TryFrom;
4use std::fs::{self, DirEntry};
5use std::io;
6use std::iter::Iterator;
7use std::path::{Path, PathBuf};
8
9/// Iterate over each font.
10#[derive(Debug)]
11pub struct FontIterator {
12  path: PathBuf,
13  cursor: usize,
14  entries: Vec<DirEntry>,
15}
16
17impl FontIterator {
18  /// Create a new instance.
19  pub fn open(dir: &Path) -> Result<Self, Error> {
20    let mut entries = vec![];
21    visit_dirs(dir, &mut entries)?;
22    Ok(Self {
23      entries,
24      path: dir.to_path_buf(),
25      cursor: 0,
26    })
27  }
28}
29
30impl Iterator for FontIterator {
31  type Item = Result<font::Font, Error>;
32
33  #[inline]
34  fn next(&mut self) -> Option<Self::Item> {
35    let entry = match self.entries.get(self.cursor) {
36      Some(entry) => entry,
37      None => return None,
38    };
39
40    let entry = font::Font::try_from(entry);
41    self.cursor += 1;
42    Some(entry)
43  }
44}
45
46fn visit_dirs(dir: &Path, entries: &mut Vec<DirEntry>) -> io::Result<()> {
47  for entry in fs::read_dir(dir)? {
48    let entry = entry?;
49    let path = entry.path();
50    if path.is_dir() {
51      visit_dirs(&path, entries)?;
52    } else if is_font(&path) {
53      entries.push(entry);
54    }
55  }
56  Ok(())
57}
58
59/// Check if a path on the directory points to a font file.
60#[inline]
61fn is_font(file: &Path) -> bool {
62  let ext = match file.extension() {
63    Some(str) => str,
64    None => return false,
65  };
66
67  let ext = match ext.to_str() {
68    Some(str) => str,
69    None => return false,
70  };
71
72  match ext {
73    "ttf" => true,
74    "otf" => true,
75    _ => false,
76  }
77}