pub trait ReadStorage {
// Required methods
fn read(&self, path: &Path) -> impl Future<Output = Result<Vec<u8>, Error>>;
fn read_to_string(
&self,
path: &Path,
) -> impl Future<Output = Result<String, Error>>;
fn read_dir(
&self,
path: &Path,
) -> impl Future<Output = Result<Vec<DirEntry>, Error>>;
fn metadata(
&self,
path: &Path,
) -> impl Future<Output = Result<Metadata, Error>>;
// Provided methods
fn try_exists(
&self,
path: &Path,
) -> impl Future<Output = Result<bool, Error>> { ... }
fn executable(
&self,
path: &Path,
) -> impl Future<Output = Result<Option<bool>, Error>> { ... }
fn read_link(
&self,
path: &Path,
) -> impl Future<Output = Result<Option<PathBuf>, Error>> { ... }
}Expand description
The read half of an async filesystem backend: everything the traversal core needs, and nothing that can change a byte on disk.
The split from Storage is not decoration — it is what lets a tree be
depended on by a consumer that must not, and cannot, write: a language
server, a renderer, a browser viewer. A backend that implements only this
is a provably read-only view, checked by the compiler rather than by
review.
Each method mirrors the std::fs function of the same name.
try_exists has a default in terms of metadata.
Required Methods§
Sourcefn read(&self, path: &Path) -> impl Future<Output = Result<Vec<u8>, Error>>
fn read(&self, path: &Path) -> impl Future<Output = Result<Vec<u8>, Error>>
Read the entire contents of a file as bytes. Mirrors std::fs::read.
Sourcefn read_to_string(
&self,
path: &Path,
) -> impl Future<Output = Result<String, Error>>
fn read_to_string( &self, path: &Path, ) -> impl Future<Output = Result<String, Error>>
Read the entire contents of a file as a string. Mirrors
std::fs::read_to_string.
Provided Methods§
Sourcefn try_exists(&self, path: &Path) -> impl Future<Output = Result<bool, Error>>
fn try_exists(&self, path: &Path) -> impl Future<Output = Result<bool, Error>>
Returns Ok(true) if the path exists, Ok(false) if it does not, and
Err(_) if the check itself failed. Mirrors std::fs::try_exists.
Sourcefn executable(
&self,
path: &Path,
) -> impl Future<Output = Result<Option<bool>, Error>>
fn executable( &self, path: &Path, ) -> impl Future<Output = Result<Option<bool>, Error>>
Whether the file at path can be run — or None where that is not a
thing this backend has.
None is the load-bearing answer, and it is declined, never guessed:
a backend that cannot observe the bit — Windows, InMemoryFs, a
document provider handing over opaque blobs — must not answer false,
because “not executable” and “I do not model this” are different facts,
and a consumer restoring modes across two machines must be able to tell
them apart rather than take turns flipping a bit neither can see. The
default is the decline, so a backend with no opinion is already correct.
Follows symlinks, like metadata.
Sourcefn read_link(
&self,
path: &Path,
) -> impl Future<Output = Result<Option<PathBuf>, Error>>
fn read_link( &self, path: &Path, ) -> impl Future<Output = Result<Option<PathBuf>, Error>>
What the symbolic link at path points at, read rather than
followed — or None where this backend models no links at all.
Mirrors std::fs::read_link, with the decline folded in.
Ok(None) is reserved for the decline, exactly as
executable’s is: it means there is no such
thing here, it is the default’s answer, and an implementation that does
model links must never give it. Such an implementation answers with the
target, or with an error where the path holds no link — which is what
readlink already does, and what lets one call settle whether links
exist at all. Reading the link is what makes recording one safe;
following it would make the thing at the other end look like a file of
this tree.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl<S> ReadStorage for &Swhere
S: ReadStorage + ?Sized,
A borrowed ReadStorage is itself a ReadStorage — so an owned backend
can be lent to something generic over S: ReadStorage without moving it or
wrapping it in an Arc the caller doesn’t otherwise need.
impl<S> ReadStorage for &Swhere
S: ReadStorage + ?Sized,
A borrowed ReadStorage is itself a ReadStorage — so an owned backend
can be lent to something generic over S: ReadStorage without moving it or
wrapping it in an Arc the caller doesn’t otherwise need.
Every member is forwarded explicitly. The matching Storage forwarding
below does the same for the durability members, where leaving any to
inherit the trait’s defaults would silently downgrade a real backend’s
guarantees the moment it was borrowed.
async fn read(&self, path: &Path) -> Result<Vec<u8>, Error>
async fn read_to_string(&self, path: &Path) -> Result<String, Error>
async fn read_dir(&self, path: &Path) -> Result<Vec<DirEntry>, Error>
async fn metadata(&self, path: &Path) -> Result<Metadata, Error>
async fn try_exists(&self, path: &Path) -> Result<bool, Error>
async fn executable(&self, path: &Path) -> Result<Option<bool>, Error>
async fn read_link(&self, path: &Path) -> Result<Option<PathBuf>, Error>
Source§impl<S> ReadStorage for Arc<S>where
S: ReadStorage + ?Sized,
An Arc<S> is itself a ReadStorage on the same terms as &S above — so
a backend shared across several owners (several open handles, a
multi-tab web client) still carries its real capabilities through the
Arc, rather than an adapter that forgot to unwrap it silently degrading
to the pessimistic defaults.
impl<S> ReadStorage for Arc<S>where
S: ReadStorage + ?Sized,
An Arc<S> is itself a ReadStorage on the same terms as &S above — so
a backend shared across several owners (several open handles, a
multi-tab web client) still carries its real capabilities through the
Arc, rather than an adapter that forgot to unwrap it silently degrading
to the pessimistic defaults.
Arc<S> derefs to S exactly like &S does, so the same explicit,
every-member forwarding applies for the same reason: the trait’s defaults
must never be reached by accident.