From a7ca474a2f2237e67a3716f9736522589ba58e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Fri, 6 Oct 2017 16:07:11 +0200 Subject: [PATCH] Add FatDir::iter() method returning dir entries iterator. FatDir is no longer iterator. Change allows to iterate over directory and still be able to use it. --- examples/ls.rs | 2 +- src/dir.rs | 90 ++++++++++++++++++++++----------------- src/file.rs | 2 +- src/fs.rs | 1 + tests/integration-test.rs | 8 ++-- 5 files changed, 58 insertions(+), 45 deletions(-) diff --git a/examples/ls.rs b/examples/ls.rs index 0a3b442..0d95307 100644 --- a/examples/ls.rs +++ b/examples/ls.rs @@ -32,7 +32,7 @@ fn main() { Some(ref path) if path == "." => root_dir, Some(ref path) => root_dir.open_dir(&path).unwrap(), }; - for r in dir { + for r in dir.iter() { let e = r.unwrap(); let modified = e.modified().format("%Y-%m-%d %H:%M:%S").to_string(); println!("{:4} {} {}", format_file_size(e.len()), modified, e.file_name()); diff --git a/src/dir.rs b/src/dir.rs index 5fe901d..25f4c9a 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Date, TimeZone, Local}; use fs::{FatFileSystemRef, FatSlice}; use file::FatFile; +#[derive(Clone)] pub(crate) enum FatDirReader<'a, 'b: 'a> { File(FatFile<'a, 'b>), Root(FatSlice<'a, 'b>), @@ -174,6 +175,7 @@ impl <'a, 'b> fmt::Debug for FatDirEntry<'a, 'b> { } } +#[derive(Clone)] pub struct FatDir<'a, 'b: 'a> { rdr: FatDirReader<'a, 'b>, fs: FatFileSystemRef<'a, 'b>, @@ -185,10 +187,56 @@ impl <'a, 'b> FatDir<'a, 'b> { FatDir { rdr, fs } } - pub fn rewind(&mut self) { - self.rdr.seek(SeekFrom::Start(0)).unwrap(); + pub fn iter(&self) -> FatDirIter<'a, 'b> { + FatDirIter { + rdr: self.rdr.clone(), + fs: self.fs.clone(), + } } + fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) { + let mut path_split = path.trim_matches('/').splitn(2, "/"); + let comp = path_split.next().unwrap(); + let rest_opt = path_split.next(); + (comp, rest_opt) + } + + fn find_entry(&mut self, name: &str) -> io::Result> { + for r in self.iter() { + let e = r?; + if e.file_name().eq_ignore_ascii_case(name) { + return Ok(e); + } + } + Err(io::Error::new(ErrorKind::NotFound, "file not found")) + } + + pub fn open_dir(&mut self, path: &str) -> io::Result> { + let (name, rest_opt) = Self::split_path(path); + let e = self.find_entry(name)?; + match rest_opt { + Some(rest) => e.to_dir().open_dir(rest), + None => Ok(e.to_dir()) + } + } + + pub fn open_file(&mut self, path: &str) -> io::Result> { + let (name, rest_opt) = Self::split_path(path); + let e = self.find_entry(name)?; + match rest_opt { + Some(rest) => e.to_dir().open_file(rest), + None => Ok(e.to_file()) + } + } +} + +#[derive(Clone)] +pub struct FatDirIter<'a, 'b: 'a> { + rdr: FatDirReader<'a, 'b>, + fs: FatFileSystemRef<'a, 'b>, +} + +impl <'a, 'b> FatDirIter<'a, 'b> { fn read_dir_entry_data(&mut self) -> io::Result { let mut name = [0; 11]; self.rdr.read(&mut name)?; @@ -224,45 +272,9 @@ impl <'a, 'b> FatDir<'a, 'b> { Ok(FatDirEntryData::File(data)) } } - - fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) { - let mut path_split = path.trim_matches('/').splitn(2, "/"); - let comp = path_split.next().unwrap(); - let rest_opt = path_split.next(); - (comp, rest_opt) - } - - fn find_entry(&mut self, name: &str) -> io::Result> { - self.rewind(); - for r in self { - let e = r?; - if e.file_name().eq_ignore_ascii_case(name) { - return Ok(e); - } - } - Err(io::Error::new(ErrorKind::NotFound, "file not found")) - } - - pub fn open_dir(&mut self, path: &str) -> io::Result> { - let (name, rest_opt) = Self::split_path(path); - let e = self.find_entry(name)?; - match rest_opt { - Some(rest) => e.to_dir().open_dir(rest), - None => Ok(e.to_dir()) - } - } - - pub fn open_file(&mut self, path: &str) -> io::Result> { - let (name, rest_opt) = Self::split_path(path); - let e = self.find_entry(name)?; - match rest_opt { - Some(rest) => e.to_dir().open_file(rest), - None => Ok(e.to_file()) - } - } } -impl <'a, 'b> Iterator for FatDir<'a, 'b> { +impl <'a, 'b> Iterator for FatDirIter<'a, 'b> { type Item = io::Result>; fn next(&mut self) -> Option { diff --git a/src/file.rs b/src/file.rs index a6a5202..afda65f 100644 --- a/src/file.rs +++ b/src/file.rs @@ -5,7 +5,7 @@ use std::io; use fs::FatFileSystemRef; - +#[derive(Clone)] pub struct FatFile<'a, 'b: 'a> { first_cluster: u32, size: Option, diff --git a/src/fs.rs b/src/fs.rs index d0d23f1..1ae6922 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -226,6 +226,7 @@ impl <'a> FatFileSystem<'a> { } } +#[derive(Clone)] pub(crate) struct FatSlice<'a, 'b: 'a> { begin: u64, size: u64, diff --git a/tests/integration-test.rs b/tests/integration-test.rs index 255106b..fbb89da 100644 --- a/tests/integration-test.rs +++ b/tests/integration-test.rs @@ -21,14 +21,14 @@ fn call_with_fs(f: &Fn(FatFileSystem) -> (), filename: &str) { fn test_root_dir(fs: FatFileSystem) { let root_dir = fs.root_dir(); - let entries = root_dir.map(|r| r.unwrap()).collect::>(); + let entries = root_dir.iter().map(|r| r.unwrap()).collect::>(); let short_names = entries.iter().map(|e| e.short_file_name()).collect::>(); assert_eq!(short_names, ["LONG.TXT", "SHORT.TXT", "VERY", "VERY-L~1"]); let names = entries.iter().map(|e| e.file_name()).collect::>(); assert_eq!(names, ["long.txt", "short.txt", "very", "very-long-dir-name"]); // Try read again - //let names2 = root_dir.map(|r| r.unwrap().file_name()).collect::>(); - //assert_eq!(names2, names); + let names2 = root_dir.iter().map(|r| r.unwrap().file_name()).collect::>(); + assert_eq!(names2, names); } #[test] @@ -106,7 +106,7 @@ fn test_read_long_file_fat32() { fn test_get_dir_by_path(fs: FatFileSystem) { let mut root_dir = fs.root_dir(); let dir = root_dir.open_dir("very/long/path/").unwrap(); - let names = dir.map(|r| r.unwrap().file_name()).collect::>(); + let names = dir.iter().map(|r| r.unwrap().file_name()).collect::>(); assert_eq!(names, [".", "..", "test.txt"]); }