summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-06-20 13:39:42 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-06-20 13:39:42 +0200
commit2996c5219345854ca8682338b205e426771565af (patch)
treee5fd62b459da0af97ad982b524528893b04ef129
parentacb6e899dfd5565eac364951074f27e48ad8a9a7 (diff)
buffered-reader: Add constructors to File that wrap std::fs::File.
- This allows for some low-level manipulation of the File object before it is wrapped. This allows one to stat(2) the file to get the file size, or to implement metadata-based caching. - We do not allow access to the File object once it is wrapped. There are three reasons for this. First, if we mmap(2) the file, we do not keep the File object around. Second, any mutations may or may not be reflected in the data returned from the BufferedReader interface, or may interfere with us reading the data. Third, even just destructuring into the File seems brittle at best because the state of the File will be unpredictable. - Fixes #1025.
-rw-r--r--buffered-reader/NEWS4
-rw-r--r--buffered-reader/src/file_generic.rs32
-rw-r--r--buffered-reader/src/file_unix.rs37
3 files changed, 68 insertions, 5 deletions
diff --git a/buffered-reader/NEWS b/buffered-reader/NEWS
index 44f485df..b115a958 100644
--- a/buffered-reader/NEWS
+++ b/buffered-reader/NEWS
@@ -2,6 +2,10 @@
#+TITLE: buffered-reader NEWS – history of user-visible changes
#+STARTUP: content hidestars
+* Changes in 1.3.0
+** New functionality
+ - File::new
+ - File::new_with_cookie
* Changes in 1.2.0
** Notable changes
- BufferedReader::copy is like std::io::copy, but more efficient.
diff --git a/buffered-reader/src/file_generic.rs b/buffered-reader/src/file_generic.rs
index 135266dd..8ad42744 100644
--- a/buffered-reader/src/file_generic.rs
+++ b/buffered-reader/src/file_generic.rs
@@ -31,6 +31,20 @@ impl<C: fmt::Debug + Sync + Send> fmt::Debug for File<C> {
}
impl File<()> {
+ /// Wraps a [`fs::File`].
+ ///
+ /// The given `path` should be the path that has been used to
+ /// obtain `file` from. It is used in error messages to provide
+ /// context to the user.
+ ///
+ /// While this is slightly less convenient than [`Self::open`], it
+ /// allows one to inspect or manipulate the [`fs::File`] object
+ /// before handing it off. For example, one can inspect the
+ /// metadata.
+ pub fn new<P: AsRef<Path>>(file: fs::File, path: P) -> io::Result<Self> {
+ Self::new_with_cookie(file, path.as_ref(), ())
+ }
+
/// Opens the given file.
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Self::with_cookie(path, ())
@@ -38,11 +52,27 @@ impl File<()> {
}
impl<C: fmt::Debug + Sync + Send> File<C> {
+ /// Like [`Self::new`], but sets a cookie.
+ ///
+ /// The given `path` should be the path that has been used to
+ /// obtain `file` from. It is used in error messages to provide
+ /// context to the user.
+ ///
+ /// While this is slightly less convenient than
+ /// [`Self::with_cookie`], it allows one to inspect or manipulate
+ /// the [`fs::File`] object before handing it off. For example,
+ /// one can inspect the metadata.
+ pub fn new_with_cookie<P: AsRef<Path>>(file: fs::File, path: P, cookie: C)
+ -> io::Result<Self> {
+ let path = path.as_ref();
+ Ok(File(Generic::with_cookie(file, None, cookie), path.into()))
+ }
+
/// Like [`Self::open`], but sets a cookie.
pub fn with_cookie<P: AsRef<Path>>(path: P, cookie: C) -> io::Result<Self> {
let path = path.as_ref();
let file = fs::File::open(path).map_err(|e| FileError::new(path, e))?;
- Ok(File(Generic::with_cookie(file, None, cookie), path.into()))
+ Self::new_with_cookie(file, path, cookie)
}
}
diff --git a/buffered-reader/src/file_unix.rs b/buffered-reader/src/file_unix.rs
index 05067de6..ee4f94d5 100644
--- a/buffered-reader/src/file_unix.rs
+++ b/buffered-reader/src/file_unix.rs
@@ -96,6 +96,20 @@ impl<'a, C: fmt::Debug + Sync + Send> fmt::Debug for Imp<'a, C> {
}
impl<'a> File<'a, ()> {
+ /// Wraps a [`fs::File`].
+ ///
+ /// The given `path` should be the path that has been used to
+ /// obtain `file` from. It is used in error messages to provide
+ /// context to the user.
+ ///
+ /// While this is slightly less convenient than [`Self::open`], it
+ /// allows one to inspect or manipulate the [`fs::File`] object
+ /// before handing it off. For example, one can inspect the
+ /// metadata.
+ pub fn new<P: AsRef<Path>>(file: fs::File, path: P) -> io::Result<Self> {
+ Self::new_with_cookie(file, path.as_ref(), ())
+ }
+
/// Opens the given file.
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Self::with_cookie(path, ())
@@ -103,8 +117,18 @@ impl<'a> File<'a, ()> {
}
impl<'a, C: fmt::Debug + Sync + Send> File<'a, C> {
- /// Like [`Self::open`], but sets a cookie.
- pub fn with_cookie<P: AsRef<Path>>(path: P, cookie: C) -> io::Result<Self> {
+ /// Like [`Self::new`], but sets a cookie.
+ ///
+ /// The given `path` should be the path that has been used to
+ /// obtain `file` from. It is used in error messages to provide
+ /// context to the user.
+ ///
+ /// While this is slightly less convenient than
+ /// [`Self::with_cookie`], it allows one to inspect or manipulate
+ /// the [`fs::File`] object before handing it off. For example,
+ /// one can inspect the metadata.
+ pub fn new_with_cookie<P: AsRef<Path>>(file: fs::File, path: P, cookie: C)
+ -> io::Result<Self> {
let path = path.as_ref();
// As fallback, we use a generic reader.
@@ -115,8 +139,6 @@ impl<'a, C: fmt::Debug + Sync + Send> File<'a, C> {
path.into()))
};
- let file = fs::File::open(path).map_err(|e| FileError::new(path, e))?;
-
// For testing and benchmarking purposes, we use the variable
// SEQUOIA_DONT_MMAP to turn off mmapping.
if ::std::env::var_os("SEQUOIA_DONT_MMAP").is_some() {
@@ -158,6 +180,13 @@ impl<'a, C: fmt::Debug + Sync + Send> File<'a, C> {
path.into(),
))
}
+
+ /// Like [`Self::open`], but sets a cookie.
+ pub fn with_cookie<P: AsRef<Path>>(path: P, cookie: C) -> io::Result<Self> {
+ let path = path.as_ref();
+ let file = fs::File::open(path).map_err(|e| FileError::new(path, e))?;
+ Self::new_with_cookie(file, path, cookie)
+ }
}
impl<'a, C: fmt::Debug + Sync + Send> io::Read for File<'a, C> {