Created
August 21, 2019 09:10
-
-
Save matklad/edd119db4434774695d30491dc5cb428 to your computer and use it in GitHub Desktop.
VFS API for Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::path::Path; | |
/// VFS provides two benefits over using `fs: | |
/// | |
/// * consistent snapshots: reading the same file twice is guranteed to return | |
/// the same result, unless you explicitly advance the revision of VFS | |
/// * automated file watching: if you read a file or a dir, you will be notified when the | |
/// file changes. | |
struct Vfs {} | |
/// Files are represented by integer handles. This is to avoid costly string | |
/// hashing and comparison when storing files in maps. | |
/// | |
/// In a sense, `VFile` is an interned `PathBuf` | |
struct VFile(u32); | |
impl VFile { | |
fn contents(self, vfs: &Vfs) -> &[u8] {} | |
fn path(self, vfs: &Vfs) -> &Path {} | |
} | |
/// Not sure if it makes sense to differentiate between files & dirs on the type | |
/// level. | |
struct VDir(u32); | |
impl VDir { | |
fn path(self, vfs: &Vfs) -> &Path {} | |
fn list(self, vfs: &Vfs) -> impl Iterator<Item = Either<VFile, VDir>> + '_; | |
fn walk(self, vfs: &Vfs, exclude: impl Fn(&Path) -> bool) -> impl Iterator<Item = Either<VFile, VDir>> + '_; | |
} | |
struct VfsDiff { | |
// Should probably differentiate between created/changed/renamed. | |
// What does `VFile` mean for a file which has been deleted? | |
changed_files: Vec<VFile>, | |
changed_dirs: Vec<Dir>, | |
} | |
impl Vfs { | |
fn new(on_error: impl Fn(&Path, io::Error)) -> Vfs { | |
// Starts background watcher thread | |
} | |
fn get_file(&self, path: &Path) -> Option<VFile> {} | |
fn get_dir(&self, path: &Path) -> Option<VDir> {} | |
/// Watcher thread does not directly commit changes to VFS | |
fn commit_pending_changes(&mut self) -> VfsDiff {} | |
/// This somehow needs to be a `select!` able API. | |
/// I'd rather *not* use futures for the time being, so something like | |
/// `fn pending_changes() -> crossbeam_channel::Receiver<()>` might work? | |
fn has_pending_changes(&self) -> bool { | |
} | |
/// Overlays (ie, files which are changed in the editor, but no on disk). I | |
/// *think* they can be built on top, but it would also be useful to have | |
/// them built-in. | |
/// | |
/// Note that these functions don't actually change the VFS, like the | |
/// watcher, they only signal pending changes. `commit_pending_changes` must | |
/// be used to actually retrieve what's new. | |
/// contents is optional to encode files which are deleted in the editor, | |
/// but are still on disk. Again, it's unclear what `VFile` means for such | |
/// semi-zombie files. | |
fn add_file_overlay(&mut self, path: &Path, initial_contents: Option<Vec<u8>>) -> VFile; | |
fn change_file_overlay(&mut self, file: VFile, new_contents: Option<Vec<u8>>); | |
/// Advanced function for file modification, for cases where the client | |
/// sends a file diff. This unfortunaltelly will have to modify the file | |
/// in-place, bypassing the `pending_changes` infra. | |
fn raw_change_file_overlay(&mut self, file: VFile) -> &mut Vec<u8>; | |
fn remove_file_overlay(&mut self, file: VFile); | |
} | |
impl Drop for Vfs { | |
fn drop() { | |
// terminates background watcher thread | |
} | |
} | |
fn main(requests: Receiver<Request>) { | |
let mut vfs = Vfs::new(); | |
let mut app_state = State::new(); | |
loop { | |
let event = select! { | |
req = requests.recv() -> Event::Request(req), | |
() = vfs.pending_changes() => Event::VfsChange, | |
}; | |
match event { | |
Event::Request(req) => handle_request(&vfs, &mut app_state, req), | |
Event::VfsChange => { | |
let changes = vfs.commit_pending_changes(); | |
invalidate_caches(&mut app_state, changes) | |
} | |
} | |
} | |
} | |
/// This receives an `&Vfs`, which guarantees repeatable read of file system | |
/// contents. | |
fn handle_request(vfs: &Vfs, state: &mut AppState, request: Request) { | |
} | |
fn invalidate_caches(state: &mut AppState, changes: VfsDiff) { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment