From 781f9e8043e62096fdf5d170060049c685cdbbbb Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 15 Dec 2024 13:45:05 +0000 Subject: [PATCH] feat(fs)!: Reader now supports non-utf8 files - reader() now returns a Result - Reader::as_str() now returns a Result - Reader::lines() now returns a Result --- examples/get.rs | 5 +++-- src/fs/reader.rs | 16 ++++++++-------- src/fs/result.rs | 3 +++ tests/fs.rs | 6 +++--- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/examples/get.rs b/examples/get.rs index 2e39427..530f19b 100644 --- a/examples/get.rs +++ b/examples/get.rs @@ -89,7 +89,7 @@ fn read_file(file: &FileHandle) -> kxio::Result<()> { // Creates a `Reader` which loaded the file into memory. let reader: kxio::fs::Reader = file.reader()?; - let contents: &str = reader.as_str(); + let contents: &str = reader.as_str()?; println!("{contents}"); Ok(()) @@ -106,6 +106,7 @@ fn delete_file(file: FileHandle) -> kxio::Result<()> { #[cfg(test)] mod tests { + use assert2::let_assert; use http::StatusCode; use super::*; @@ -146,7 +147,7 @@ mod tests { // Read the file let file = fs.file(&file_path); let reader = file.reader().expect("reader"); - let contents = reader.as_str(); + let_assert!(Ok(contents) = reader.as_str()); assert_eq!(contents, "contents"); diff --git a/src/fs/reader.rs b/src/fs/reader.rs index 8cdb6a6..79ce7c1 100644 --- a/src/fs/reader.rs +++ b/src/fs/reader.rs @@ -8,13 +8,13 @@ use super::Error; /// A reader for a file. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct Reader { - contents: String, + contents: Vec, } impl Reader { #[tracing::instrument] pub(super) fn new(path: &Path) -> Result { tracing::debug!("std::fs::read_to_string"); - let contents = std::fs::read_to_string(path).map_err(Error::Io)?; + let contents = std::fs::read(path).map_err(Error::Io)?; tracing::debug!(len = contents.len(), "contents"); Ok(Self { contents }) } @@ -32,8 +32,8 @@ impl Reader { /// # Ok(()) /// # } /// ``` - pub fn as_str(&self) -> &str { - &self.contents + pub fn as_str(&self) -> Result<&str> { + std::str::from_utf8(&self.contents).map_err(Error::Utf8Error) } /// Returns an iterator over the lines in the file. @@ -49,8 +49,8 @@ impl Reader { /// # Ok(()) /// # } /// ``` - pub fn lines(&self) -> Lines<'_> { - self.contents.lines() + pub fn lines(&self) -> Result> { + self.as_str().map(|s| s.lines()) } /// Returns the contents of the file as bytes. @@ -67,11 +67,11 @@ impl Reader { /// # } /// ``` pub fn bytes(&self) -> &[u8] { - self.contents.as_bytes() + &self.contents } } impl Display for Reader { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.contents) + write!(f, "{}", self.as_str().map_err(|_| std::fmt::Error)?) } } diff --git a/src/fs/result.rs b/src/fs/result.rs index 9e924b5..d7505d3 100644 --- a/src/fs/result.rs +++ b/src/fs/result.rs @@ -12,6 +12,8 @@ pub enum Error { IoString(String), + Utf8Error(std::str::Utf8Error), + #[display("Path access attempted outside of base ({base:?}): {path:?}")] PathTraversal { base: PathBuf, @@ -34,6 +36,7 @@ impl Clone for Error { match self { Error::Io(err) => Error::IoString(err.to_string()), Error::IoString(err) => Error::IoString(err.clone()), + Error::Utf8Error(err) => Error::Utf8Error(*err), Error::PathTraversal { base, path } => Error::PathTraversal { base: base.clone(), path: path.clone(), diff --git a/tests/fs.rs b/tests/fs.rs index 65dafd8..24f9dff 100644 --- a/tests/fs.rs +++ b/tests/fs.rs @@ -723,7 +723,7 @@ mod file { file.write(&contents).expect("write"); let reader = file.reader().expect("reader"); - let string = reader.as_str(); + let string = reader.as_str().expect("as_str"); assert_eq!(string, contents); } @@ -743,7 +743,7 @@ mod file { file.write(&contents).expect("write"); let reader = file.reader().expect("reader"); - let lines = reader.lines().collect::>(); + let lines = reader.lines().expect("lines").collect::>(); assert_eq!(lines, vec!["line 1", "line 2", &line3]); } @@ -759,7 +759,7 @@ mod file { file.write("line 1\nline 2").expect("write"); let reader = file.reader().expect("reader"); - let lines = reader.lines().collect::>(); + let lines = reader.lines().expect("lines").collect::>(); assert_eq!(lines, vec!["line 1", "line 2"]);