1use std::{
2 fs, io,
3 path::{Path, PathBuf},
4};
5
6use ts_path::DisplayPath;
7
8#[derive(Debug)]
10#[non_exhaustive]
11#[allow(missing_docs)]
12pub enum ReadFileError {
13 #[non_exhaustive]
14 DoesNotExist { path: PathBuf },
15
16 #[non_exhaustive]
17 NotAFile { path: PathBuf },
18
19 #[non_exhaustive]
20 ReadError { path: PathBuf, source: io::Error },
21}
22impl core::fmt::Display for ReadFileError {
23 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24 match &self {
25 Self::DoesNotExist { path, .. } => {
26 write!(f, "`{}` does not exist", path.opinionated_display())
27 }
28 Self::NotAFile { path, .. } => {
29 write!(f, "`{}` is not a file", path.opinionated_display())
30 }
31 Self::ReadError { path, .. } => {
32 write!(f, "could not read `{}`", path.opinionated_display())
33 }
34 }
35 }
36}
37impl core::error::Error for ReadFileError {
38 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
39 match &self {
40 Self::ReadError { source, .. } => Some(source),
41 _ => None,
42 }
43 }
44}
45impl ReadFileError {
46 #[allow(missing_docs)]
47 pub(crate) fn read_error(source: io::Error, path: &Path) -> Self {
48 Self::ReadError {
49 path: path.to_path_buf(),
50 source,
51 }
52 }
53}
54
55pub fn read_file(path: &Path) -> Result<Vec<u8>, ReadFileError> {
57 if !fs::exists(path).map_err(|source| ReadFileError::read_error(source, path))? {
58 return Err(ReadFileError::DoesNotExist {
59 path: path.to_path_buf(),
60 });
61 }
62
63 let metadata = path
64 .metadata()
65 .map_err(|source| ReadFileError::read_error(source, path))?;
66
67 if metadata.is_dir() {
68 return Err(ReadFileError::NotAFile {
69 path: path.to_path_buf(),
70 });
71 }
72
73 fs::read(path).map_err(|source| ReadFileError::read_error(source, path))
74}
75
76pub fn read_file_to_string(path: &Path) -> Result<String, ReadFileError> {
78 if !fs::exists(path).map_err(|source| ReadFileError::read_error(source, path))? {
79 return Err(ReadFileError::DoesNotExist {
80 path: path.to_path_buf(),
81 });
82 }
83
84 let metadata = path
85 .metadata()
86 .map_err(|source| ReadFileError::read_error(source, path))?;
87
88 if metadata.is_dir() {
89 return Err(ReadFileError::NotAFile {
90 path: path.to_path_buf(),
91 });
92 }
93
94 fs::read_to_string(path).map_err(|source| ReadFileError::read_error(source, path))
95}