use crate::{file::File, DirEntry};
use std::fs;
use std::path::Path;
#[derive(Debug, Clone, PartialEq)]
pub struct Dir<'a> {
path: &'a str,
entries: &'a [DirEntry<'a>],
}
impl<'a> Dir<'a> {
pub const fn new(path: &'a str, entries: &'a [DirEntry<'a>]) -> Self {
Dir { path, entries }
}
pub fn path(&self) -> &'a Path {
Path::new(self.path)
}
pub const fn entries(&self) -> &'a [DirEntry<'a>] {
self.entries
}
pub fn files(&self) -> impl Iterator<Item = &'a File<'a>> + 'a {
self.entries().iter().filter_map(DirEntry::as_file)
}
pub fn dirs(&self) -> impl Iterator<Item = &'a Dir<'a>> + 'a {
self.entries().iter().filter_map(DirEntry::as_dir)
}
pub fn get_entry<S: AsRef<Path>>(&self, path: S) -> Option<&'a DirEntry<'a>> {
let path = path.as_ref();
for entry in self.entries() {
if entry.path() == path {
return Some(entry);
}
if let DirEntry::Dir(d) = entry {
if let Some(nested) = d.get_entry(path) {
return Some(nested);
}
}
}
None
}
pub fn get_file<S: AsRef<Path>>(&self, path: S) -> Option<&'a File<'a>> {
self.get_entry(path).and_then(DirEntry::as_file)
}
pub fn get_dir<S: AsRef<Path>>(&self, path: S) -> Option<&'a Dir<'a>> {
self.get_entry(path).and_then(DirEntry::as_dir)
}
pub fn contains<S: AsRef<Path>>(&self, path: S) -> bool {
self.get_entry(path).is_some()
}
pub fn extract<S: AsRef<Path>>(&self, base_path: S) -> std::io::Result<()> {
let base_path = base_path.as_ref();
for entry in self.entries() {
let path = base_path.join(entry.path());
match entry {
DirEntry::Dir(d) => {
fs::create_dir_all(&path)?;
d.extract(base_path)?;
}
DirEntry::File(f) => {
fs::write(path, f.contents())?;
}
}
}
Ok(())
}
}