Skip to content

Commit

Permalink
Fleshed out the WASI runner use case
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-F-Bryan committed Mar 14, 2023
1 parent 163d56b commit 154a795
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 176 deletions.
9 changes: 6 additions & 3 deletions lib/vfs/src/filesystem_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub trait FileSystemExt {
}

#[async_trait::async_trait]
impl<F: FileSystem> FileSystemExt for F {
impl<F: FileSystem + ?Sized> FileSystemExt for F {
fn exists(&self, path: impl AsRef<Path>) -> bool {
self.metadata(path.as_ref()).is_ok()
}
Expand Down Expand Up @@ -112,7 +112,7 @@ impl<F: FileSystem> FileSystemExt for F {
let _ = self
.new_open_options()
.create(true)
.append(true)
.write(true)
.open(path)?;

Ok(())
Expand Down Expand Up @@ -140,7 +140,10 @@ impl<F: FileSystem> FileSystemExt for F {
}
}

fn create_dir_all(fs: &impl FileSystem, path: &Path) -> Result<(), FsError> {
fn create_dir_all<F>(fs: &F, path: &Path) -> Result<(), FsError>
where
F: FileSystem + ?Sized,
{
if let Some(parent) = path.parent() {
create_dir_all(fs, parent)?;
}
Expand Down
124 changes: 69 additions & 55 deletions lib/vfs/src/filesystems.rs
Original file line number Diff line number Diff line change
@@ -1,90 +1,104 @@
use crate::FileSystem;
use std::ops::ControlFlow;

/// A chain of one or more [`FileSystem`]s.
// FIXME(Michael-F-Bryan): We could remove this trait's HRTBs and lifetimes if
// we had access to GATs, but our MSRV is currently 1.64 and GATs require 1.65.
pub trait FileSystems<'a>: 'a {
type Iter: IntoIterator<Item = &'a dyn FileSystem> + 'a;

fn iter_filesystems(&'a self) -> Self::Iter;
pub trait FileSystems {
// FIXME(Michael-F-Bryan): Rewrite this to use GATs and an external iterator
// when we bump the MSRV to 1.65 or higher.
fn for_each_filesystems<F, Ret>(&self, func: F) -> Option<Ret>
where
F: FnMut(&dyn FileSystem) -> ControlFlow<Ret>;
}

impl<'a, S> FileSystems<'a> for &'a S
impl<'b, S> FileSystems for &'b S
where
S: FileSystems<'a> + 'a,
S: FileSystems + 'b,
{
type Iter = <S as FileSystems<'a>>::Iter;

fn iter_filesystems(&'a self) -> Self::Iter {
(**self).iter_filesystems()
fn for_each_filesystems<F, Ret>(&self, func: F) -> Option<Ret>
where
F: FnMut(&dyn FileSystem) -> ControlFlow<Ret>,
{
(**self).for_each_filesystems(func)
}
}

impl<'a, F> FileSystems<'a> for Vec<F>
impl<T> FileSystems for Vec<T>
where
F: FileSystem + 'a,
T: FileSystem,
{
type Iter = std::iter::Map<std::slice::Iter<'a, F>, fn(&F) -> &dyn FileSystem>;

fn iter_filesystems(&'a self) -> Self::Iter {
fn downcast<T: FileSystem>(value: &T) -> &dyn FileSystem {
value
}
self.iter().map(downcast)
fn for_each_filesystems<F, Ret>(&self, func: F) -> Option<Ret>
where
F: FnMut(&dyn FileSystem) -> ControlFlow<Ret>,
{
self[..].for_each_filesystems(func)
}
}

impl<'a, F, const N: usize> FileSystems<'a> for [F; N]
impl<T, const N: usize> FileSystems for [T; N]
where
F: FileSystem + 'a,
T: FileSystem,
{
type Iter = [&'a dyn FileSystem; N];

fn iter_filesystems(&'a self) -> Self::Iter {
// a poor man's version of the unstable array::each_ref()
let mut i = 0;
[(); N].map(|()| {
let f = &self[i] as &dyn FileSystem;
i += 1;
f
})
fn for_each_filesystems<F, Ret>(&self, func: F) -> Option<Ret>
where
F: FnMut(&dyn FileSystem) -> ControlFlow<Ret>,
{
self[..].for_each_filesystems(func)
}
}

impl<'a> FileSystems<'a> for () {
type Iter = std::iter::Empty<&'a dyn FileSystem>;
impl<T> FileSystems for [T]
where
T: FileSystem,
{
fn for_each_filesystems<F, Ret>(&self, mut func: F) -> Option<Ret>
where
F: FnMut(&dyn FileSystem) -> ControlFlow<Ret>,
{
for fs in self.iter() {
match func(fs) {
ControlFlow::Continue(_) => continue,
ControlFlow::Break(result) => return Some(result),
}
}

fn iter_filesystems(&'a self) -> Self::Iter {
std::iter::empty()
None
}
}

macro_rules! count {
($($t:ident),* $(,)?) => {
0 $( + count!(@$t) )*
};
(@$t:ident) => { 1 };
impl FileSystems for () {
fn for_each_filesystems<F, Ret>(&self, _func: F) -> Option<Ret>
where
F: FnMut(&dyn FileSystem) -> ControlFlow<Ret>,
{
None
}
}

macro_rules! tuple_filesystems {
($first:ident $(, $rest:ident)* $(,)?) => {
impl<'a, $first, $( $rest ),*> FileSystems<'a> for ($first, $($rest),*)
impl<$first, $( $rest ),*> FileSystems for ($first, $($rest),*)
where
$first: FileSystem + 'a,
$($rest: FileSystem + 'a),*
$first: FileSystem,
$($rest: FileSystem),*
{
type Iter = [ &'a dyn FileSystem; { count!($first, $($rest),*) }];

fn iter_filesystems(&'a self) -> Self::Iter {
fn for_each_filesystems<F, Ret>(&self, mut func: F) -> Option<Ret>
where
F: FnMut(&dyn FileSystem) -> ControlFlow<Ret>,
{
#[allow(non_snake_case)]
let ($first, $($rest),*) = &self;

[
$first as &dyn FileSystem,
$(
$rest as &dyn FileSystem,
)*
]
if let ControlFlow::Break(result) = func($first) {
return Some(result);
}

$(
if let ControlFlow::Break(result) = func($rest) {
return Some(result);
}
)*

None
}
}

Expand All @@ -93,4 +107,4 @@ macro_rules! tuple_filesystems {
() => {};
}

tuple_filesystems!(A, B, C, D, E, F, G, H, I, J, K);
tuple_filesystems!(F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16,);
35 changes: 0 additions & 35 deletions lib/vfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::any::Any;
use std::ffi::OsString;
use std::fmt;
use std::io;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::task::Context;
Expand Down Expand Up @@ -94,40 +93,6 @@ impl dyn FileSystem + 'static {
}
}

impl<P, F> FileSystem for P
where
P: Deref<Target = F> + std::fmt::Debug + Send + Sync + 'static,
F: FileSystem + ?Sized,
{
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
(**self).read_dir(path)
}

fn create_dir(&self, path: &Path) -> Result<()> {
(**self).create_dir(path)
}

fn remove_dir(&self, path: &Path) -> Result<()> {
(**self).remove_dir(path)
}

fn rename(&self, from: &Path, to: &Path) -> Result<()> {
(**self).rename(from, to)
}

fn metadata(&self, path: &Path) -> Result<Metadata> {
(**self).metadata(path)
}

fn remove_file(&self, path: &Path) -> Result<()> {
(**self).remove_file(path)
}

fn new_open_options(&self) -> OpenOptions {
(**self).new_open_options()
}
}

pub trait FileOpener {
fn open(
&self,
Expand Down
Loading

0 comments on commit 154a795

Please sign in to comment.