use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use std::fmt::Debug;
use std::fs::{self, File};
use std::io::{self, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};
use std::time::{Duration, SystemTime};
use time::macros::format_description;
use time::OffsetDateTime;
fn path_reader<P>(path: P) -> BufReader<File>
where
P: AsRef<Path> + Debug,
{
BufReader::new(File::open(&path).unwrap_or_else(|err| {
panic!("Could not open file for reading: {:?} -- {}", path, err)
}))
}
fn path_writer<P>(path: P) -> BufWriter<File>
where
P: AsRef<Path> + Debug,
{
BufWriter::new(File::create(&path).unwrap_or_else(|err| {
panic!("Could not open file for writing: {:?} -- {}", path, err)
}))
}
pub fn file_exists<P>(path: P) -> bool
where
P: AsRef<Path> + Debug,
{
path.as_ref().exists()
}
pub fn from_json_file<P, T>(path: P) -> T
where
P: AsRef<Path> + Debug,
T: DeserializeOwned,
{
serde_json::from_reader(path_reader(&path)).unwrap_or_else(|err| {
panic!("Could not read JSON from {:?} -- {}", path, err)
})
}
pub fn to_json_file<P, T>(path: P, data: T)
where
P: AsRef<Path> + Debug,
T: Serialize,
{
let mut writer = path_writer(&path);
serde_json::to_writer_pretty(&mut writer, &data).unwrap_or_else(|err| {
panic!("Could not write JSON to {:?} -- {}", path, err)
});
writeln!(&mut writer).unwrap_or_else(|err| {
format!("Could not append newline to file: {:?} -- {}", &path, err);
});
}
pub fn lines_to_file<P>(path: P, lines: Vec<String>)
where
P: AsRef<Path> + Debug,
{
let mut writer = path_writer(&path);
for line in &lines {
writeln!(writer, "{}", line).unwrap();
}
}
pub fn paths_in(dir: &str) -> impl Iterator<Item = String> + '_ {
fs::read_dir(PathBuf::from(dir))
.unwrap_or_else(|err| {
panic!("couldn't view files in directory: {} ({})", dir, err)
})
.map(move |file| {
file.unwrap_or_else(|err| {
panic!("error viewing file in directory: {} ({})", dir, err)
})
})
.map(|file| file.path().into_os_string())
.map(|osstr| {
osstr.into_string().unwrap_or_else(|err| {
panic!("found file path with invalid unicode ({:?})", err)
})
})
}
pub fn walk_dirs_rec<F: FnMut(&Path)>(
dir: &Path,
cb: &mut F,
) -> io::Result<()> {
if dir.is_dir() {
cb(dir);
for entry in fs::read_dir(dir)? {
let path = entry?.path();
walk_dirs_rec(&path, cb)?;
}
}
Ok(())
}
pub fn time_since(t: &SystemTime) -> Duration {
t.elapsed().unwrap_or_else(|err| {
eprintln!(
"Warning: SystemTime elapsed failed (was system clock reset?): {}",
err
);
Duration::ZERO
})
}
pub fn current_datetime_str() -> String {
let dt: OffsetDateTime = SystemTime::now().into();
let dt_fmt =
format_description!("[year]-[month]-[day]-[hour][minute][second]");
dt.format(&dt_fmt).unwrap()
}
#[test]
fn test_current_datetime_str() {
let cur = current_datetime_str();
println!("Current datetime string: {}", cur);
let chars: Vec<char> = cur.chars().collect();
assert_eq!(chars.len(), 17);
assert_eq!(chars[0], '2');
assert_eq!(chars[1], '0');
for i in [2, 3, 5, 6, 8, 9, 11, 12, 13, 14, 15, 16] {
assert!(chars[i].is_ascii_digit());
}
for i in [4, 7, 10] {
assert_eq!(chars[i], '-');
}
}
pub trait FreshClone {
type Result: Iterator;
fn fresh_clone(self) -> Self::Result;
}
impl<I: Iterator> FreshClone for I {
type Result = std::vec::IntoIter<I::Item>;
fn fresh_clone(self) -> Self::Result {
self.collect::<Vec<I::Item>>().into_iter()
}
}
#[test]
fn test_fresh_clone_1() {
let v1: Vec<usize> = vec![1, 2, 3];
let r1: Vec<usize> = v1.iter().fresh_clone().copied().collect();
assert_eq!(v1, r1);
assert_eq!(r1.len(), 3);
let r2: Vec<usize> = Vec::new().iter().fresh_clone().copied().collect();
assert!(r2.is_empty());
let r3: Vec<usize> =
v1.iter().chain(v1.iter()).fresh_clone().copied().collect();
assert_eq!(r3, vec![1, 2, 3, 1, 2, 3]);
}
#[test]
fn test_fresh_clone_2() {
let mut v: Vec<usize> = vec![1, 2, 3];
for i in v.iter().copied().fresh_clone() {
v.retain(|&x| x != i);
}
assert!(v.is_empty());
}