isideload-vfs 0.0.1

A virtual filesystem for isideload
Documentation
use crate::traits::{OpenOptionsConfig, VfsMetadata, VfsPermissions};
use crate::with_vfs;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};

#[derive(Debug)]
pub struct File {
    inner: Box<dyn crate::traits::VfsFile>,
}

impl File {
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
        OpenOptions::new().read(true).open(path)
    }

    pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
        OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
    }

    pub fn options() -> OpenOptions {
        OpenOptions::new()
    }

    pub fn set_len(&self, size: u64) -> io::Result<()> {
        self.inner.set_len(size)
    }

    pub fn metadata(&self) -> io::Result<Metadata> {
        self.inner.metadata().map(|inner| Metadata { inner })
    }

    pub fn set_permissions(&mut self, perm: Permissions) -> io::Result<()> {
        self.inner.set_permissions(perm.inner)
    }

    pub fn sync_all(&mut self) -> io::Result<()> {
        self.inner.sync_all()
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.read(buf)
    }
}
impl Write for File {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}
impl Seek for File {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        self.inner.seek(pos)
    }
}

#[derive(Clone, Default)]
pub struct OpenOptions {
    config: OpenOptionsConfig,
}

impl OpenOptions {
    pub fn new() -> Self {
        Self {
            config: OpenOptionsConfig::default(),
        }
    }
    pub fn read(&mut self, read: bool) -> &mut Self {
        self.config.read = read;
        self
    }
    pub fn write(&mut self, write: bool) -> &mut Self {
        self.config.write = write;
        self
    }
    pub fn create(&mut self, create: bool) -> &mut Self {
        self.config.create = create;
        self
    }
    pub fn create_new(&mut self, create_new: bool) -> &mut Self {
        self.config.create_new = create_new;
        self
    }
    pub fn append(&mut self, append: bool) -> &mut Self {
        self.config.append = append;
        self
    }
    pub fn truncate(&mut self, truncate: bool) -> &mut Self {
        self.config.truncate = truncate;
        self
    }
    pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
        with_vfs(|vfs| {
            vfs.open_file(path.as_ref(), &self.config)
                .map(|inner| File { inner })
        })
    }
}

pub struct Metadata {
    inner: Box<dyn VfsMetadata>,
}

#[derive(Clone, Copy)]
pub struct FileType {
    is_dir: bool,
    is_file: bool,
    is_symlink: bool,
}

impl FileType {
    pub fn is_dir(&self) -> bool {
        self.is_dir
    }
    pub fn is_file(&self) -> bool {
        self.is_file
    }
    pub fn is_symlink(&self) -> bool {
        self.is_symlink
    }
}

impl Metadata {
    pub fn is_dir(&self) -> bool {
        self.inner.is_dir()
    }
    pub fn is_file(&self) -> bool {
        self.inner.is_file()
    }
    pub fn is_symlink(&self) -> bool {
        self.inner.is_symlink()
    }
    pub fn len(&self) -> u64 {
        self.inner.len()
    }
    pub fn permissions(&self) -> Permissions {
        Permissions {
            inner: self.inner.permissions(),
        }
    }
    pub fn file_type(&self) -> FileType {
        FileType {
            is_dir: self.is_dir(),
            is_file: self.is_file(),
            is_symlink: self.is_symlink(),
        }
    }
}

pub struct Permissions {
    inner: Box<dyn VfsPermissions>,
}

impl Permissions {
    pub fn readonly(&self) -> bool {
        self.inner.readonly()
    }
    pub fn set_readonly(&mut self, readonly: bool) {
        self.inner.set_readonly(readonly)
    }
}

pub trait PermissionsExt {
    fn mode(&self) -> u32;
    fn set_mode(&mut self, mode: u32);
}

impl PermissionsExt for Permissions {
    fn mode(&self) -> u32 {
        self.inner.mode()
    }
    fn set_mode(&mut self, mode: u32) {
        self.inner.set_mode(mode)
    }
}

pub trait MetadataExt {
    fn dev(&self) -> u64;
    fn ino(&self) -> u64;
    fn mode(&self) -> u32;
    fn nlink(&self) -> u64;
    fn uid(&self) -> u32;
    fn gid(&self) -> u32;
    fn rdev(&self) -> u64;
    fn size(&self) -> u64;
    fn atime(&self) -> i64;
    fn atime_nsec(&self) -> i64;
    fn mtime(&self) -> i64;
    fn mtime_nsec(&self) -> i64;
    fn ctime(&self) -> i64;
    fn ctime_nsec(&self) -> i64;
    fn blksize(&self) -> u64;
    fn blocks(&self) -> u64;
}

impl MetadataExt for Metadata {
    fn dev(&self) -> u64 {
        self.inner.dev()
    }
    fn ino(&self) -> u64 {
        self.inner.ino()
    }
    fn mode(&self) -> u32 {
        self.inner.mode()
    }
    fn nlink(&self) -> u64 {
        self.inner.nlink()
    }
    fn uid(&self) -> u32 {
        self.inner.uid()
    }
    fn gid(&self) -> u32 {
        self.inner.gid()
    }
    fn rdev(&self) -> u64 {
        self.inner.rdev()
    }
    fn size(&self) -> u64 {
        self.inner.size()
    }
    fn atime(&self) -> i64 {
        self.inner.atime()
    }
    fn atime_nsec(&self) -> i64 {
        self.inner.atime_nsec()
    }
    fn mtime(&self) -> i64 {
        self.inner.mtime()
    }
    fn mtime_nsec(&self) -> i64 {
        self.inner.mtime_nsec()
    }
    fn ctime(&self) -> i64 {
        self.inner.ctime()
    }
    fn ctime_nsec(&self) -> i64 {
        self.inner.ctime_nsec()
    }
    fn blksize(&self) -> u64 {
        self.inner.blksize()
    }
    fn blocks(&self) -> u64 {
        self.inner.blocks()
    }
}

pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
    with_vfs(|vfs| vfs.read(path.as_ref()))
}

pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
    with_vfs(|vfs| vfs.write(path.as_ref(), contents.as_ref()))
}

pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
    with_vfs(|vfs| vfs.copy(from.as_ref(), to.as_ref()))
}

pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
    with_vfs(|vfs| vfs.rename(from.as_ref(), to.as_ref()))
}

pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
    with_vfs(|vfs| vfs.remove_file(path.as_ref()))
}

pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
    with_vfs(|vfs| vfs.remove_dir(path.as_ref()))
}

pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
    with_vfs(|vfs| vfs.remove_dir_all(path.as_ref()))
}

pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
    with_vfs(|vfs| vfs.create_dir(path.as_ref()))
}

pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
    with_vfs(|vfs| vfs.create_dir_all(path.as_ref()))
}

pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
    with_vfs(|vfs| vfs.read_link(path.as_ref()))
}

pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
    with_vfs(|vfs| vfs.metadata(path.as_ref()).map(|inner| Metadata { inner }))
}

pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
    with_vfs(|vfs| {
        vfs.symlink_metadata(path.as_ref())
            .map(|inner| Metadata { inner })
    })
}

pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
    with_vfs(|vfs| vfs.set_permissions(path.as_ref(), perm.inner))
}

pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(target: P, link: Q) -> io::Result<()> {
    with_vfs(|vfs| vfs.symlink(target.as_ref(), link.as_ref()))
}

#[derive(Debug)]
pub struct ReadDir {
    entries: std::vec::IntoIter<PathBuf>,
}

impl Iterator for ReadDir {
    type Item = io::Result<DirEntry>;
    fn next(&mut self) -> Option<Self::Item> {
        self.entries.next().map(|path| Ok(DirEntry { path }))
    }
}

pub struct DirEntry {
    path: PathBuf,
}

impl DirEntry {
    pub fn path(&self) -> PathBuf {
        self.path.clone()
    }
    pub fn file_name(&self) -> std::ffi::OsString {
        self.path.file_name().unwrap_or_default().to_os_string()
    }
    pub fn file_type(&self) -> io::Result<FileType> {
        metadata(&self.path).map(|meta| meta.file_type())
    }
    pub fn metadata(&self) -> io::Result<Metadata> {
        symlink_metadata(&self.path)
    }
}

pub trait DirEntryExt {
    fn ino(&self) -> u64;
}

impl DirEntryExt for DirEntry {
    fn ino(&self) -> u64 {
        self.metadata().map(|m| m.ino()).unwrap_or(0)
    }
}

pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
    with_vfs(|vfs| {
        let entries = vfs.read_dir(path.as_ref())?;
        Ok(ReadDir {
            entries: entries.into_iter(),
        })
    })
}

pub fn temp_dir() -> PathBuf {
    crate::with_vfs(|vfs| Ok(vfs.temp_dir())).unwrap_or_else(|_| PathBuf::from("/"))
}