1use std::fmt::Display;
2use std::path::{Path, PathBuf};
3use std::{fs, io};
4
5use serde::Deserialize;
6
7#[derive(Debug)]
8#[non_exhaustive]
9pub struct FromFileError {
10 pub path: PathBuf,
11 pub kind: FromFileErrorKind,
12}
13
14impl Display for FromFileError {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 write!(f, "unable to read file {:?}", self.path)
17 }
18}
19
20impl std::error::Error for FromFileError {
21 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
22 match &self.kind {
23 FromFileErrorKind::ReadFile(err) => Some(err),
24 FromFileErrorKind::Parse(err) => Some(err),
25 }
26 }
27}
28
29#[derive(Debug)]
30pub enum FromFileErrorKind {
31 ReadFile(io::Error),
32 Parse(serde_json::Error),
33}
34
35pub(crate) fn read_json_from_file<T>(filename: &Path) -> Result<T, FromFileError>
36where
37 for<'de> T: Deserialize<'de>,
38{
39 let string = fs::read_to_string(filename).map_err(|err| FromFileError {
43 path: filename.to_owned(),
44 kind: FromFileErrorKind::ReadFile(err),
45 })?;
46 serde_json::from_str(&string).map_err(|err| FromFileError {
47 path: filename.to_owned(),
48 kind: FromFileErrorKind::Parse(err),
49 })
50}