use std::path::Path; use time::OffsetDateTime; #[derive(Debug)] pub struct TimeDb { data: Vec, } impl TimeDb { pub fn load>(path: P) -> Self { let file = std::fs::read_to_string(path).unwrap(); let mut data = vec![]; for line in file.lines() { let it = TimedFile::parse_line(line); data.push(it); } Self { data } } pub fn get_times(&self, path: &str) -> Option<&TimedFile> { for file in &self.data { if &file.path == path { return Some(file); } } None } } #[derive(Debug)] pub struct TimedFile { path: String, pub creation: Option, pub modification: Option, pub access: Option, } impl TimedFile { pub fn parse_line>(raw: S) -> Self { let mut values = raw.as_ref().rsplitn(4, ",").collect::>(); values.reverse(); let to_odt = |str: &&str| -> Option { str.parse::() .ok() .map(|t| OffsetDateTime::from_unix_timestamp(t as i64).unwrap()) }; let path = unescape(values[0]); let creation = values.get(1).map(to_odt).flatten(); let modification = values.get(2).map(to_odt).flatten(); let access = values.get(3).map(to_odt).flatten(); Self { path, creation, modification, access, } } } // Permissive unescape. Everything that's not \\ or \, is passed // unchanged, while those get their slash removed fn unescape>(raw: S) -> String { let raw = raw.as_ref(); if !raw.contains('\\') { return raw.to_owned(); } let mut unescape = String::with_capacity(raw.len()); let mut escaped = false; for ch in raw.chars() { match (escaped, ch) { (false, '\\') => { escaped = true; } (false, c) => unescape.push(c), (true, '\\') | (true, ',') => { unescape.push(ch); escaped = false; } (true, c) => { unescape.push('\\'); unescape.push(c); escaped = false; } } } unescape }