1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
use std::fs::File; use std::io::{self, BufRead, BufReader}; use std::path::Path; #[derive(Debug, Error)] pub enum LoaderError { #[error("error reading line in loader conf")] Line(#[source] io::Error), #[error("loader conf is not a file")] NotAFile, #[error("default was defined without a value")] NoValueForDefault, #[error("timeout was defined without a value")] NoValueForTimeout, #[error("error opening loader file")] Open(#[source] io::Error), #[error("timeout was defined with a value ({}) which is not a number", _0)] TimeoutNaN(String), } #[derive(Debug, Default, Clone)] pub struct LoaderConf { pub default: Option<Box<str>>, pub timeout: Option<u32>, } impl LoaderConf { pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, LoaderError> { let path = path.as_ref(); let mut loader = LoaderConf::default(); if !path.exists() { return Ok(loader); } if !path.is_file() { return Err(LoaderError::NotAFile); } let file = File::open(path).map_err(LoaderError::Open)?; for line in BufReader::new(file).lines() { let line = line.map_err(LoaderError::Line)?; let mut fields = line.split_whitespace(); match fields.next() { Some("default") => match fields.next() { Some(default) => loader.default = Some(default.into()), None => return Err(LoaderError::NoValueForDefault), }, Some("timeout") => match fields.next() { Some(timeout) => { if let Ok(timeout) = timeout.parse::<u32>() { loader.timeout = Some(timeout); } else { return Err(LoaderError::TimeoutNaN(timeout.into())); } } None => return Err(LoaderError::NoValueForTimeout), }, _ => (), } } Ok(loader) } }