diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-06-20 13:39:42 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2023-06-20 13:39:42 +0200 |
commit | 2996c5219345854ca8682338b205e426771565af (patch) | |
tree | e5fd62b459da0af97ad982b524528893b04ef129 | |
parent | acb6e899dfd5565eac364951074f27e48ad8a9a7 (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/NEWS | 4 | ||||
-rw-r--r-- | buffered-reader/src/file_generic.rs | 32 | ||||
-rw-r--r-- | buffered-reader/src/file_unix.rs | 37 |
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> { |