yofi 0.2.1

minimalistic menu for wayland
Documentation
use std::borrow::Borrow;
use std::collections::HashMap;
use std::fs::File;
use std::hash::Hash;
use std::io::{BufRead, BufReader, Write};
use std::path::Path;

pub struct Usage(HashMap<String, usize>);

impl Usage {
    pub fn from_path(path: impl AsRef<Path>) -> Self {
        let usage = crate::desktop::xdg_dirs()
            .place_cache_file(path)
            .and_then(File::open)
            .map_err(|e| {
                if e.kind() != std::io::ErrorKind::NotFound {
                    log::error!("cannot open cache file: {}", e)
                }
            })
            .map(BufReader::new)
            .into_iter()
            .flat_map(|rdr| {
                rdr.lines()
                    .filter(|l| l.as_ref().map(|l| !l.is_empty()).unwrap_or(true))
                    .map(|l| {
                        let line = l.map_err(|e| {
                            log::error!("unable to read the line from cache: {}", e)
                        })?;
                        let mut iter = line.split(' ');
                        let (count, entry) = (iter.next().ok_or(())?, iter.next().ok_or(())?);

                        let count = count.parse().map_err(|e| {
                            log::error!(
                                "invalid cache file, unable to parse count (\"{}\"): {}",
                                count,
                                e
                            )
                        })?;

                        Ok((entry.to_string(), count))
                    })
            })
            .collect::<Result<_, ()>>()
            .unwrap_or_default();

        Self(usage)
    }

    pub fn entry_count<Q: ?Sized>(&self, entry: &Q) -> usize
    where
        String: Borrow<Q>,
        Q: Hash + Eq,
    {
        self.0.get(entry).copied().unwrap_or(0)
    }

    pub fn increment_entry_usage(&mut self, entry: String) {
        *self.0.entry(entry).or_default() += 1;
    }

    pub fn try_update_cache(&self, path: impl AsRef<Path>) {
        if let Err(e) = crate::desktop::xdg_dirs()
            .place_cache_file(path)
            .and_then(File::create)
            .and_then(|mut f| {
                let mut buf = vec![];

                for (entry, count) in &self.0 {
                    let s = format!("{} ", count);
                    buf.extend(s.as_bytes());
                    buf.extend(entry.as_bytes());
                    buf.push(b'\n');
                }

                f.write_all(&buf)
            })
        {
            log::error!("failed to update cache: {}", e);
        }
    }
}