typescript_tools/
io.rs

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    // Reading a file into a string before invoking Serde is faster than
40    // invoking Serde from a BufReader, see
41    // https://github.com/serde-rs/json/issues/160
42    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}