use std::{
ffi::OsStr,
fmt::Debug,
path::{Path, PathBuf},
};
use crate::sys::{MemfsEntry, StdfsEntry};
pub trait Entry: Debug+Send+Sync+'static
{
fn path(&self) -> &Path;
fn path_buf(&self) -> PathBuf;
fn alt(&self) -> &Path;
fn alt_buf(&self) -> PathBuf;
fn rel(&self) -> &Path;
fn rel_buf(&self) -> PathBuf;
fn file_name(&self) -> Option<&OsStr>
{
self.path().file_name()
}
fn follow(self, follow: bool) -> VfsEntry;
fn following(&self) -> bool;
fn is_exec(&self) -> bool
{
self.mode() & 0o111 != 0
}
fn is_dir(&self) -> bool;
fn is_file(&self) -> bool;
fn is_readonly(&self) -> bool
{
self.mode() & 0o222 == 0
}
fn is_symlink(&self) -> bool;
fn is_symlink_dir(&self) -> bool
{
self.is_symlink() && self.is_dir()
}
fn is_symlink_file(&self) -> bool
{
self.is_symlink() && self.is_file()
}
fn mode(&self) -> u32;
fn upcast(self) -> VfsEntry;
}
#[derive(Debug)]
pub enum VfsEntry
{
Stdfs(StdfsEntry),
Memfs(MemfsEntry),
}
impl Clone for VfsEntry
{
fn clone(&self) -> Self
{
match self {
VfsEntry::Stdfs(x) => VfsEntry::Stdfs(x.clone()),
VfsEntry::Memfs(x) => VfsEntry::Memfs(x.clone()),
}
}
}
impl Entry for VfsEntry
{
fn path(&self) -> &Path
{
match self {
VfsEntry::Stdfs(x) => x.path(),
VfsEntry::Memfs(x) => x.path(),
}
}
fn path_buf(&self) -> PathBuf
{
match self {
VfsEntry::Stdfs(x) => x.path_buf(),
VfsEntry::Memfs(x) => x.path_buf(),
}
}
fn alt(&self) -> &Path
{
match self {
VfsEntry::Stdfs(x) => x.alt(),
VfsEntry::Memfs(x) => x.alt(),
}
}
fn alt_buf(&self) -> PathBuf
{
match self {
VfsEntry::Stdfs(x) => x.alt_buf(),
VfsEntry::Memfs(x) => x.alt_buf(),
}
}
fn rel(&self) -> &Path
{
match self {
VfsEntry::Stdfs(x) => x.rel(),
VfsEntry::Memfs(x) => x.rel(),
}
}
fn rel_buf(&self) -> PathBuf
{
match self {
VfsEntry::Stdfs(x) => x.rel_buf(),
VfsEntry::Memfs(x) => x.rel_buf(),
}
}
fn follow(self, follow: bool) -> VfsEntry
{
match self {
VfsEntry::Stdfs(x) => x.follow(follow).upcast(),
VfsEntry::Memfs(x) => x.follow(follow).upcast(),
}
}
fn following(&self) -> bool
{
match self {
VfsEntry::Stdfs(x) => x.following(),
VfsEntry::Memfs(x) => x.following(),
}
}
fn is_dir(&self) -> bool
{
match self {
VfsEntry::Stdfs(x) => x.is_dir(),
VfsEntry::Memfs(x) => x.is_dir(),
}
}
fn is_file(&self) -> bool
{
match self {
VfsEntry::Stdfs(x) => x.is_file(),
VfsEntry::Memfs(x) => x.is_file(),
}
}
fn is_readonly(&self) -> bool
{
match self {
VfsEntry::Stdfs(x) => x.is_readonly(),
VfsEntry::Memfs(x) => x.is_readonly(),
}
}
fn is_symlink(&self) -> bool
{
match self {
VfsEntry::Stdfs(x) => x.is_symlink(),
VfsEntry::Memfs(x) => x.is_symlink(),
}
}
fn mode(&self) -> u32
{
match self {
VfsEntry::Stdfs(x) => x.mode(),
VfsEntry::Memfs(x) => x.mode(),
}
}
fn upcast(self) -> VfsEntry
{
match self {
VfsEntry::Stdfs(x) => x.upcast(),
VfsEntry::Memfs(x) => x.upcast(),
}
}
}
#[cfg(test)]
mod tests
{
use crate::prelude::*;
#[test]
fn test_vfs_entry_alt_rel()
{
test_entry_alt_rel(assert_vfs_setup!(Vfs::memfs()));
test_entry_alt_rel(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_alt_rel((vfs, tmpdir): (Vfs, PathBuf))
{
let dir1 = tmpdir.mash("dir1");
let link1 = tmpdir.mash("link1");
assert_vfs_mkdir_p!(vfs, &dir1);
assert_vfs_symlink!(vfs, &link1, &dir1);
let entry = vfs.entry(&link1).unwrap();
assert_eq!(entry.alt(), &dir1);
assert_eq!(entry.alt_buf(), dir1);
assert_eq!(entry.rel(), Path::new("dir1"));
assert_eq!(entry.rel_buf(), PathBuf::from("dir1"));
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_is_dir()
{
test_entry_is_dir(assert_vfs_setup!(Vfs::memfs()));
test_entry_is_dir(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_is_dir((vfs, tmpdir): (Vfs, PathBuf))
{
let dir1 = tmpdir.mash("dir1");
let file1 = tmpdir.mash("file1");
assert_vfs_mkfile!(vfs, &file1);
assert_eq!(vfs.entry(&file1).unwrap().is_dir(), false);
assert_vfs_mkdir_p!(vfs, &dir1);
assert_eq!(vfs.entry(&dir1).unwrap().is_dir(), true);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_is_file()
{
test_entry_is_file(assert_vfs_setup!(Vfs::memfs()));
test_entry_is_file(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_is_file((vfs, tmpdir): (Vfs, PathBuf))
{
let dir1 = tmpdir.mash("dir1");
let file1 = tmpdir.mash("file1");
assert_vfs_mkdir_p!(vfs, &dir1);
assert_eq!(vfs.entry(&dir1).unwrap().is_file(), false);
assert_vfs_mkfile!(vfs, &file1);
assert_eq!(vfs.entry(&file1).unwrap().is_file(), true);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_is_readonly()
{
test_entry_is_readonly(assert_vfs_setup!(Vfs::memfs()));
test_entry_is_readonly(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_is_readonly((vfs, tmpdir): (Vfs, PathBuf))
{
let file1 = tmpdir.mash("file1");
assert_vfs_mkfile!(vfs, &file1);
assert_eq!(vfs.entry(&file1).unwrap().is_readonly(), false);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_is_symlink()
{
test_entry_is_symlink(assert_vfs_setup!(Vfs::memfs()));
test_entry_is_symlink(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_is_symlink((vfs, tmpdir): (Vfs, PathBuf))
{
let dir1 = tmpdir.mash("dir1");
let link1 = tmpdir.mash("link1");
assert_vfs_mkdir_p!(vfs, &dir1);
assert_eq!(vfs.entry(&dir1).unwrap().is_symlink(), false);
assert_vfs_symlink!(vfs, &link1, &dir1);
assert_eq!(vfs.entry(&link1).unwrap().is_symlink(), true);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_is_symlink_dir()
{
test_entry_is_symlink_dir(assert_vfs_setup!(Vfs::memfs()));
test_entry_is_symlink_dir(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_is_symlink_dir((vfs, tmpdir): (Vfs, PathBuf))
{
let dir1 = tmpdir.mash("dir1");
let link1 = tmpdir.mash("link1");
assert_vfs_mkdir_p!(vfs, &dir1);
assert_eq!(vfs.entry(&dir1).unwrap().is_symlink_dir(), false);
assert_vfs_symlink!(vfs, &link1, &dir1);
assert_eq!(vfs.entry(&link1).unwrap().is_symlink_dir(), true);
assert_eq!(vfs.entry(&link1).unwrap().is_symlink_file(), false);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_is_symlink_file()
{
test_entry_is_symlink_file(assert_vfs_setup!(Vfs::memfs()));
test_entry_is_symlink_file(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_is_symlink_file((vfs, tmpdir): (Vfs, PathBuf))
{
let file1 = tmpdir.mash("file1");
let link1 = tmpdir.mash("link1");
assert_vfs_mkfile!(vfs, &file1);
assert_eq!(vfs.entry(&file1).unwrap().is_symlink_file(), false);
assert_vfs_symlink!(vfs, &link1, &file1);
assert_eq!(vfs.entry(&link1).unwrap().is_symlink_dir(), false);
assert_eq!(vfs.entry(&link1).unwrap().is_symlink_file(), true);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_follow()
{
test_entry_follow(assert_vfs_setup!(Vfs::memfs()));
test_entry_follow(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_follow((vfs, tmpdir): (Vfs, PathBuf))
{
let file1 = tmpdir.mash("file1");
let link1 = tmpdir.mash("link1");
assert_vfs_mkfile!(vfs, &file1);
assert_vfs_symlink!(vfs, &link1, &file1);
let entry = vfs.entry(&link1).unwrap();
assert_eq!(entry.path(), &link1);
assert_eq!(entry.following(), false);
let entry = entry.follow(true);
assert_eq!(entry.path(), &file1);
assert_eq!(entry.following(), true);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_entry_upcast()
{
test_entry_upcast(assert_vfs_setup!(Vfs::memfs()));
test_entry_upcast(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_entry_upcast((vfs, tmpdir): (Vfs, PathBuf))
{
let file1 = tmpdir.mash("file1");
assert_vfs_mkfile!(vfs, &file1);
assert_eq!(vfs.entry(&file1).unwrap().upcast().path(), &file1);
assert_vfs_remove_all!(vfs, &tmpdir);
}
}