Update file/dir structure to be more robust
parent
d363bbfc1a
commit
6acc77e52e
@ -0,0 +1,177 @@
|
|||||||
|
pub struct Permissions {
|
||||||
|
pub can_read: bool,
|
||||||
|
pub can_write: bool,
|
||||||
|
pub can_exec: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DirEntry {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub permissions: Permissions,
|
||||||
|
pub item: DirEntryContents
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum DirEntryContents {
|
||||||
|
Directory(Directory),
|
||||||
|
File(File)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Directory {
|
||||||
|
entries : Vec<DirEntry>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct File {
|
||||||
|
pub contents: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DirError {
|
||||||
|
pub filename: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Directory {
|
||||||
|
pub fn get_entry_by_name(&self, name : &str) -> Result<&DirEntry, DirError> {
|
||||||
|
for entry in self.entries.iter() {
|
||||||
|
if entry.name == name {
|
||||||
|
return Ok(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(DirError {
|
||||||
|
filename: name.to_string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entry_by_path(&self, path : &str) -> Result<&DirEntry, DirError> {
|
||||||
|
let mut segments = path.split("/").filter(|s| !s.is_empty());
|
||||||
|
let first_seg = segments.next().expect("Path has no segments!");
|
||||||
|
let remaining_path = segments.fold(String::new(), |mut a, b| {
|
||||||
|
a.reserve(b.len() + 1);
|
||||||
|
a.push_str("/");
|
||||||
|
a.push_str(b);
|
||||||
|
a
|
||||||
|
});
|
||||||
|
|
||||||
|
console_log!("In dir, getting {}. first_seg: {}. remaining: {}", path, first_seg, remaining_path);
|
||||||
|
|
||||||
|
let entry = self.get_entry_by_name(first_seg)?;
|
||||||
|
|
||||||
|
if remaining_path.is_empty() {
|
||||||
|
console_log!("Found entry! {}", entry.name);
|
||||||
|
return Ok(entry);
|
||||||
|
} else if entry.is_dir() {
|
||||||
|
console_log!("Found dir: {}", entry.name);
|
||||||
|
return entry.as_dir().unwrap().get_entry_by_path(remaining_path.as_str())
|
||||||
|
} else {
|
||||||
|
console_log!("Error accessing: {}", first_seg);
|
||||||
|
return Err(DirError {
|
||||||
|
filename: first_seg.to_string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entries(&self) -> impl Iterator<Item = &DirEntry> {
|
||||||
|
self.entries.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_dirs(&self) -> impl Iterator<Item = &DirEntry> {
|
||||||
|
self.entries.iter().filter(|item| item.is_dir())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_files(&self) -> impl Iterator<Item = &DirEntry> {
|
||||||
|
self.entries.iter().filter(|item| item.is_file())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirEntry {
|
||||||
|
pub fn create_dir(name: &'static str, perms: bool) -> DirEntry {
|
||||||
|
DirEntry {
|
||||||
|
name,
|
||||||
|
permissions: Permissions {
|
||||||
|
can_read: perms,
|
||||||
|
can_write: perms,
|
||||||
|
can_exec: perms
|
||||||
|
},
|
||||||
|
item: DirEntryContents::Directory(Directory {
|
||||||
|
entries: Vec::new()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_file(name: &'static str, perms: bool, contents: &'static str) -> DirEntry {
|
||||||
|
DirEntry {
|
||||||
|
name,
|
||||||
|
permissions: Permissions {
|
||||||
|
can_read: perms,
|
||||||
|
can_write: perms,
|
||||||
|
can_exec: perms
|
||||||
|
},
|
||||||
|
item: DirEntryContents::File(File {
|
||||||
|
contents
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_file(&self) -> bool {
|
||||||
|
if let DirEntryContents::File(file) = &self.item {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_dir(&self) -> bool {
|
||||||
|
!self.is_file()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_dir(&self) -> Option<&Directory> {
|
||||||
|
if let DirEntryContents::Directory(dir) = &self.item {
|
||||||
|
return Some(dir)
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_file(&self) -> Option<&File> {
|
||||||
|
if let DirEntryContents::File(file) = &self.item {
|
||||||
|
return Some(file)
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entry_by_path(&self, path : &str) -> Result<&DirEntry, DirError> {
|
||||||
|
console_log!("In entry, getting {}", path);
|
||||||
|
|
||||||
|
if path == "/" || path.is_empty() {
|
||||||
|
return Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.as_dir().expect("Cannot get entries of file").get_entry_by_path(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_fs() -> DirEntry {
|
||||||
|
let mut root = DirEntry::create_dir("root", false);
|
||||||
|
let mut home = DirEntry::create_dir("home", false);
|
||||||
|
let mut ashe = DirEntry::create_dir("ashe", true);
|
||||||
|
let mut projects = DirEntry::create_dir("projects", true);
|
||||||
|
|
||||||
|
if let DirEntryContents::Directory(ref mut dir) = projects.item {
|
||||||
|
dir.entries.push(DirEntry::create_file("~ashe", true, include_str!("../res/~ashe.md")));
|
||||||
|
dir.entries.push(DirEntry::create_file("ashe.gay", true, include_str!("../res/ashe.gay.md")));
|
||||||
|
dir.entries.push(DirEntry::create_file("tempest.dev", true, include_str!("../res/tempest.dev.md")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let DirEntryContents::Directory(ref mut dir) = ashe.item {
|
||||||
|
dir.entries.push(DirEntry::create_file("about.md", true, include_str!("../res/about.md")));
|
||||||
|
dir.entries.push(DirEntry::create_file("contact.md", true, include_str!("../res/contact.md")));
|
||||||
|
dir.entries.push(projects)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let DirEntryContents::Directory(ref mut dir) = home.item {
|
||||||
|
dir.entries.push(ashe)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let DirEntryContents::Directory(ref mut dir) = root.item {
|
||||||
|
dir.entries.push(home);
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
pub fn join(root : &str, path : &str) -> String {
|
||||||
|
if path.starts_with("/") {
|
||||||
|
return String::from_str(path).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result_segments : Vec<&str> = root.split("/").filter(|s| !s.is_empty()).collect();
|
||||||
|
let path_segments = path.split("/").filter(|s| !s.is_empty());
|
||||||
|
|
||||||
|
for segment in path_segments {
|
||||||
|
if segment == "." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if segment == ".." {
|
||||||
|
if result_segments.len() > 0 {
|
||||||
|
result_segments.pop();
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result_segments.push(segment)
|
||||||
|
}
|
||||||
|
|
||||||
|
let result_path = result_segments.iter().fold(String::new(), |mut a, b| {
|
||||||
|
a.reserve(b.len() + 1);
|
||||||
|
a.push_str("/");
|
||||||
|
a.push_str(b);
|
||||||
|
a
|
||||||
|
});
|
||||||
|
|
||||||
|
return result_path
|
||||||
|
}
|
Loading…
Reference in New Issue