lib_humus/
toml_helper.rs

1use serde::Deserialize;
2
3use std::fmt;
4use std::fs;
5use std::path::Path;
6use std::path::PathBuf;
7use std::error::Error;
8
9/// Reads from a specified filepath, parses as toml and returns as the
10/// desired deserialized type.
11///
12/// Example:
13/// ```
14/// use serde::Deserialize;
15/// use lib_humus::read_toml_from_file;
16///
17/// #[derive(Deserialize)]
18/// struct Config {
19///		name: String,
20/// }
21///
22///	let cfg: Config = read_toml_from_file("example_config.toml").unwrap();
23///	println!("Hello {}!", cfg.name);
24/// ```
25///
26pub fn read_toml_from_file<T>(path: impl AsRef<Path>) -> Result<T,TomlError>
27where T: for<'de> Deserialize<'de> {
28	let text = match fs::read_to_string(&path) {
29		Ok(t) => t,
30		Err(e) => {
31			return Err(TomlError::FileError{
32				path: path.as_ref().into(),
33				io_error: e
34			});
35		}
36	};
37	match toml::from_str(&text) {
38		Ok(t) => Ok(t),
39		Err(e) => {
40			return Err(TomlError::ParseError{
41				path: path.as_ref().into(),
42				toml_error: e
43			});
44		}
45	}
46}
47
48/// Returned when [read_toml_from_file()] fails.
49///
50/// [read_toml_from_file]: ./fn.read_toml_from_file.html
51#[derive(Debug)]
52pub enum TomlError {
53	
54	/// There was an error reading the file from the filesystem.
55	FileError{
56		/// The path the file is supposed to be at
57		path: PathBuf,
58		/// What went wrong
59		io_error: std::io::Error
60	},
61	
62	/// There was an error parsing the file content as toml.
63	ParseError{
64		/// The path the file was read from
65		path: PathBuf,
66		/// What went wrong
67		toml_error: toml::de::Error
68	},
69}
70
71impl fmt::Display for TomlError {
72	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73		match self {
74			Self::FileError{path, io_error} =>
75				write!(f,"Error while reading file '{path:?}': {io_error}"),
76			Self::ParseError{path, toml_error} =>
77				write!(f,"Unable to parse file as toml '{path:?}':\n{toml_error}"),
78		}
79	}
80}
81
82impl Error for TomlError {
83    fn source(&self) -> Option<&(dyn Error + 'static)> {
84        match self {
85			Self::FileError{io_error, ..} =>
86				Some(io_error),
87			Self::ParseError{toml_error, ..} =>
88				Some(toml_error),
89        }
90    }
91}