1use std::{
2 error::Error,
3 fmt::Display,
4 fs::File,
5 io::{self, Read},
6 path::{Path, PathBuf},
7};
8
9use serde::Deserialize;
10
11#[derive(Debug)]
12#[non_exhaustive]
13pub struct FromFileError {
14 path: PathBuf,
15 kind: FromFileErrorKind,
16}
17
18impl Display for FromFileError {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match &self.kind {
21 FromFileErrorKind::Open(_) => write!(f, "unable to open file {:?}", self.path),
22 FromFileErrorKind::Read(_) => write!(f, "unable to read file {:?}", self.path),
23 FromFileErrorKind::Parse(_) => write!(f, "unable to parse file {:?}", self.path),
24 }
25 }
26}
27
28impl Error for FromFileError {
29 fn source(&self) -> Option<&(dyn Error + 'static)> {
30 match &self.kind {
31 FromFileErrorKind::Open(err) => Some(err),
32 FromFileErrorKind::Read(err) => Some(err),
33 FromFileErrorKind::Parse(err) => Some(err),
34 }
35 }
36}
37
38#[derive(Debug)]
39pub enum FromFileErrorKind {
40 #[non_exhaustive]
41 Open(io::Error),
42 #[non_exhaustive]
43 Read(io::Error),
44 #[non_exhaustive]
45 Parse(serde_json::Error),
46}
47
48pub(crate) fn read_json_from_file<P, T>(path: P) -> Result<T, FromFileError>
49where
50 P: AsRef<Path>,
51 for<'de> T: Deserialize<'de>,
52{
53 fn inner<T>(path: &Path) -> Result<T, FromFileError>
54 where
55 for<'de> T: Deserialize<'de>,
56 {
57 (|| {
61 let mut string = String::new();
62 File::open(path)
63 .map_err(FromFileErrorKind::Open)?
64 .read_to_string(&mut string)
65 .map_err(FromFileErrorKind::Read)?;
66 let json = serde_json::from_str(&string).map_err(FromFileErrorKind::Parse)?;
67 Ok(json)
68 })()
69 .map_err(|kind| FromFileError {
70 path: path.to_owned(),
71 kind,
72 })
73 }
74 inner(path.as_ref())
75}