use std::fs::File;
use std::io::{BufReader, Write};
use std::path::{Path, PathBuf};
use serde::de::DeserializeOwned;
use crate::Error;
pub struct WriteOptions {
no_overwrite: bool,
}
pub struct WriteOptionsBuilder {
no_overwrite: bool,
}
impl WriteOptionsBuilder {
pub fn new() -> Self {
Self {
no_overwrite: false
}
}
pub fn disallow_overwrite(mut self) -> Self {
self.no_overwrite = true;
self
}
pub fn build(self) -> WriteOptions {
WriteOptions {
no_overwrite : self.no_overwrite,
}
}
}
pub fn write_to_file<T: serde::ser::Serialize>(obj: &T, dir: &str, filename: &str, options: WriteOptions) -> Result<Option<PathBuf>, Error> {
let path = Path::new(dir);
let path = path.join(filename);
if options.no_overwrite && path.exists() {
return Ok(None)
}
write_to_path(&path, obj)?;
Ok(Some(path))
}
fn write_to_path<T: serde::ser::Serialize>(path: &PathBuf, obj: &T) -> Result<(), Error> {
let mut fp = File::create(&path)?;
fp.write_all(&serde_json::ser::to_vec(obj).unwrap())
.map_err(|e| Error::IoError(e))
}
pub fn read_from_file<T: DeserializeOwned>(dir: &str, filename: impl AsRef<Path>) -> Result<T, Error> {
let path = Path::new(dir);
let path = path.join(filename);
let file = File::open(path)?;
let reader = BufReader::new(file);
let obj = serde_json::from_reader(reader)?;
Ok(obj)
}
pub(crate) fn compose_filename(prefix: &str, extension: &str, evaluation_data_number: Option<u64>) -> String {
if let Some(evaluation_data_number) = evaluation_data_number {
format!("{}-{evaluation_data_number}{}", prefix, extension)
} else {
format!("{}{}", prefix, extension)
}
}
pub(crate) fn all_files<'a>(input_dir: &str, prefix: impl AsRef<str> + 'a, extension: &'a str) -> impl Iterator<Item = Result<std::fs::DirEntry, Error>> + 'a {
let (first, second) = match std::fs::read_dir(input_dir) {
Ok(it) => (Some(it), None),
Err(e) => (None, Some(Err(e))),
};
let entries = first.into_iter().flat_map(|it| it).chain(second.into_iter());
entries.filter_map(move |item| {
let prefix = prefix.as_ref();
match item {
Ok(entry) => {
let fname = entry.file_name();
let fname = fname.to_str()?;
if !(fname.starts_with(prefix) && fname.ends_with(extension)) {
return None;
}
if fname.len() != prefix.len() + extension.len() {
let middle = &fname[(prefix.len())..(fname.len() - extension.len())];
if !middle.starts_with("-") {
return None;
}
let _: u64 = middle[1..].parse().ok()?;
}
Some(Ok(entry))
},
Err(e) => Some(Err(e.into()))
}
})
}
#[cfg(test)]
mod tests {
#[cfg(not(target_env = "sgx"))]
#[test]
fn test_all_files() {
use std::{collections::HashSet, ffi::OsString};
let a: HashSet<_> = Result::unwrap(super::all_files("./tests/data/read-dir-test", "prefix", ".ext").map(|i| i.map(|entry| entry.file_name()) ).collect());
let b: HashSet<_> = <_>::into_iter(["prefix-1.ext", "prefix-2.ext", "prefix-3.ext", "prefix.ext"]).map(|i| OsString::from(i)).collect();
assert_eq!(a, b);
}
}