The exercise I set myself was to construct an index of files, like the unix find
command. For now it just collects (filename,size,mtime) into a vector. (Later as a further exercise I'd like to e.g. dump as JSON, or put into a database, either mongo or mariadb or postgresql or all.)
I've come up with the following, which does what I want, but doesn't look to my eye like the right way to do this.
use std::fs;
use std::path::Path;
use std::time;
use walkdir::WalkDir;
#[derive(Debug)]
struct FileInfo {
name: String,
size: u64,
mtime: time::SystemTime,
}
fn main() {
let mut files_info: Vec<FileInfo> = Vec::new();
for entry in WalkDir::new(".")
.follow_links(false)
.into_iter()
.filter_map(|e| e.ok()) {
let path = entry.path();
if let Ok(metadata) = entry.metadata() {
if ! entry.path_is_symlink() {
if let Ok(mtime) = metadata.modified() {
let size = metadata.len();
if let Some(name) = path.as_os_str().to_str() {
files_info.push( FileInfo {
name: name.to_string(),
size,
mtime } )
}
}
}
}
}
for entry in files_info {
println!("{:?}",entry);
}
}
So questions:
- What is the right way to avoid excessive nesting?
- What is the right way to deal with both
Result
returning functions, andOption
returning functions? That is, if I were to refactor this out of main, what should my function return? (In particular, I should factor the construction offiles_info
into its own function, and factor the logic inside thefilter_map
into a separate function. But I'm not sure the right way to do this so far as return types is concerned? I could probably returnNone
if anything returns an error.)