#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_debug_implementations, rust_2018_idioms)]
#![deny(unreachable_pub, private_in_public)]
use crate::utils::create_random_file;
use anyhow::{Error, Result};
use serde::{Deserialize, Serialize};
use std::{fs, path::Path};
pub mod utils;
#[derive(Serialize, Deserialize, Clone, Debug, strum::Display)]
pub enum Strategy {
Simple,
Wide,
Deep,
Directory,
File,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Structure {
pub width: usize,
pub depth: usize,
pub target_size: usize,
}
impl std::str::FromStr for Strategy {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Simple" => Ok(Strategy::Simple),
"Wide" => Ok(Strategy::Wide),
"Deep" => Ok(Strategy::Deep),
"Directory" => Ok(Strategy::Directory),
"File" => Ok(Strategy::File),
_ => Err(format!("Invalid strategy: {}", s)),
}
}
}
impl Structure {
pub fn new(width: usize, depth: usize, target_size: usize, strategy: Strategy) -> Self {
match strategy {
Strategy::Wide => Structure {
width: width * 2,
depth: depth / 2,
target_size,
},
Strategy::Deep => Structure {
width: width / 2,
depth: depth * 2,
target_size,
},
Strategy::Directory => Structure {
width: 0,
depth: 0,
target_size,
},
Strategy::File => Structure {
width: 0,
depth: 0,
target_size,
},
_ => Structure {
width,
depth,
target_size,
},
}
}
pub fn to_path_string(&self) -> String {
format!("w{}_d{}_s{}", self.width, self.depth, self.target_size)
}
pub fn generate(&self, path: &Path) -> Result<(), Error> {
assert!(!path.exists());
if self.depth == 0 {
create_random_file(path, self.target_size);
return Ok(()); }
fs::create_dir(path).unwrap();
for i in 0..self.width {
let target_size = self.target_size / self.width;
let new_path = path.join(i.to_string());
Structure::new(self.width, self.depth - 1, target_size, Strategy::Simple)
.generate(&new_path)
.unwrap();
}
Ok(())
}
}