From bd8a0d67669ab55d33343c92eb21b7d95a8f7cb0 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Wed, 18 Oct 2023 14:21:04 -0700 Subject: [PATCH] state (#106) --- src/app.rs | 12 +++++-- src/io.rs | 10 ++++++ src/real_io.rs | 3 ++ src/virtual_io.rs | 85 ++++++++++++++++++++++++++++++++--------------- 4 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/app.rs b/src/app.rs index 8177d7e9..cd37ec39 100644 --- a/src/app.rs +++ b/src/app.rs @@ -84,15 +84,19 @@ fn add<'a, T: Io, S: 'a + Storage>( fn calculate_total(io: &impl Io, d: &str, extra: u64) -> io::Result { let stdout = &mut io.stdout(); - let a = io.read_dir(&("cdt0/".to_owned() + d))?; + let a = io.read_dir_type(&("cdt0/".to_owned() + d), true); + let a = match a { + Ok(a) => a, + Err(_) => return Ok(extra), + }; let an = a.len() as u64; let mut total = 0; let state = &mut State::new(stdout); for (ai, ia) in a.iter().enumerate() { - let b = io.read_dir(&ia.path())?; + let b = io.read_dir_type(&ia.path(), true)?; let bn = b.len() as u64; for (bi, ib) in b.iter().enumerate() { - let c = io.read_dir(&ib.path())?; + let c = io.read_dir_type(&ib.path(), false)?; for ic in c.iter() { let d = ic.metadata()?.len(); total += d; @@ -269,6 +273,8 @@ mod test { " Hello, world!".as_bytes(), ) .unwrap(); + io.write_recursively("cdt0/roots/ab", " Hello, world!".as_bytes()) + .unwrap(); run(&mut io).unwrap(); } diff --git a/src/io.rs b/src/io.rs index 3b30dceb..37f41be0 100644 --- a/src/io.rs +++ b/src/io.rs @@ -6,6 +6,7 @@ use std::{ #[allow(clippy::len_without_is_empty)] pub trait Metadata { fn len(&self) -> u64; + fn is_dir(&self) -> bool; } pub trait DirEntry { @@ -66,6 +67,15 @@ pub trait Io { } Ok(()) } + fn read_dir_type(&self, path: &str, is_dir: bool) -> io::Result> { + let mut result = Vec::default(); + for i in self.read_dir(path)? { + if i.metadata()?.is_dir() == is_dir { + result.push(i); + } + } + Ok(result) + } } #[cfg(test)] diff --git a/src/real_io.rs b/src/real_io.rs index 8cd2a98c..5313efdc 100644 --- a/src/real_io.rs +++ b/src/real_io.rs @@ -12,6 +12,9 @@ impl Metadata for fs::Metadata { fn len(&self) -> u64 { self.len() } + fn is_dir(&self) -> bool { + self.is_dir() + } } impl DirEntry for fs::DirEntry { diff --git a/src/virtual_io.rs b/src/virtual_io.rs index efd225a5..18a9744f 100644 --- a/src/virtual_io.rs +++ b/src/virtual_io.rs @@ -1,6 +1,6 @@ use std::{ cell::RefCell, - collections::{HashMap, HashSet}, + collections::HashMap, io::{self, Read, Write}, iter::once, rc::Rc, @@ -12,12 +12,16 @@ use crate::io::Io; #[derive(Debug, Clone)] pub struct Metadata { len: u64, + is_dir: bool, } impl crate::io::Metadata for Metadata { fn len(&self) -> u64 { self.len } + fn is_dir(&self) -> bool { + self.is_dir + } } #[derive(Debug, Default, Clone)] @@ -47,20 +51,47 @@ impl Write for VecRef { } } +#[derive(Debug, Default)] +enum Entity { + #[default] + Dir, + File(VecRef), +} + +impl Entity { + fn metadata(&self) -> Metadata { + match self { + Entity::Dir => Metadata { + len: 0, + is_dir: true, + }, + Entity::File(x) => Metadata { + len: x.0.borrow().len() as u64, + is_dir: false, + }, + } + } +} + #[derive(Debug, Default)] pub struct FileSystem { - directory_set: HashSet, - file_map: HashMap, + entity_map: HashMap, } impl FileSystem { pub fn check_dir(&self, path: &str) -> io::Result<()> { + if let Some(Entity::Dir) = self.entity_map.get(path) { + Ok(()) + } else { + Err(not_found()) + } + } + pub fn check_parent(&self, path: &str) -> io::Result<()> { if let Some(d) = path.rfind('/').map(|i| &path[..i]) { - if !self.directory_set.contains(d) { - return Err(not_found()); - } + self.check_dir(d) + } else { + Ok(()) } - Ok(()) } } @@ -156,33 +187,39 @@ impl Io for VirtualIo { } fn metadata(&self, path: &str) -> io::Result { let fs = self.fs.borrow(); - fs.file_map + fs.entity_map .get(path) - .map(|v| Metadata { - len: v.0.borrow().len() as u64, - }) + .map(Entity::metadata) .ok_or_else(not_found) } fn create(&self, path: &str) -> io::Result { let mut fs = self.fs.borrow_mut(); - fs.check_dir(path)?; + fs.check_parent(path)?; let vec_ref = VecRef::default(); check_path(path)?; - fs.file_map.insert(path.to_string(), vec_ref.clone()); + fs.entity_map + .insert(path.to_string(), Entity::File(vec_ref.clone())); Ok(MemFile::new(vec_ref)) } fn create_dir(&self, path: &str) -> io::Result<()> { let mut fs = self.fs.borrow_mut(); - fs.directory_set.insert(path.to_string()); + fs.entity_map.insert(path.to_string(), Entity::Dir); Ok(()) } fn open(&self, path: &str) -> io::Result { let fs = self.fs.borrow(); - fs.check_dir(path)?; + fs.check_parent(path)?; check_path(path)?; - fs.file_map + fs.entity_map .get(path) - .map(|v| MemFile::new(v.clone())) + .map(|v| { + if let Entity::File(x) = v { + Some(MemFile::new(x.to_owned())) + } else { + None + } + }) + .flatten() .ok_or_else(not_found) } fn stdout(&self) -> VecRef { @@ -191,17 +228,11 @@ impl Io for VirtualIo { fn read_dir(&self, path: &str) -> io::Result> { let fs = self.fs.borrow(); - let d = fs.directory_set.iter().map(|d| DirEntry { - path: d.to_string(), - metadata: Metadata { len: 0 }, - }); - let f = fs.file_map.iter().map(|(k, v)| DirEntry { - path: k.to_owned(), - metadata: Metadata { - len: v.0.borrow().len() as u64, - }, + fs.check_dir(path)?; + let i = fs.entity_map.iter().map(|(p, e)| DirEntry { + path: p.to_owned(), + metadata: e.metadata(), }); - let i = d.chain(f); let x = i .filter(|p| { if let Some((a, _)) = p.path.rsplit_once('/') {