1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use crate::{PathWithContent, Result};
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use rayon::prelude::*;
use std::ffi::OsStr;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{
fs::File,
io::{BufReader, Read},
path::PathBuf,
};
static INPUTTED_FILE_NUMBER: AtomicUsize = AtomicUsize::new(0);
const BUFFER_SIZR: usize = 16 * 1024;
trait PathExt {
fn without_dotted_prefix(&self) -> bool;
fn add_dotted_prefix(&mut self);
}
impl PathExt for PathBuf {
fn without_dotted_prefix(&self) -> bool {
self.is_relative() && !self.starts_with("../") && !self.starts_with("./")
}
fn add_dotted_prefix(&mut self) {
*self = PathBuf::from_iter([OsStr::new("./"), self.as_os_str()]);
}
}
pub fn read_files(paths: Vec<PathBuf>) -> Result<PathWithContent> {
println!("Reading files / Getting content from stdin:");
let result = paths
.into_par_iter()
.filter(|path| path.is_file() || path.as_os_str() == "-")
.map(|mut path| {
let should_read_from_input = path.as_os_str() == "-";
let content = get_content(&path, should_read_from_input);
if path.without_dotted_prefix() {
path.add_dotted_prefix();
}
if should_read_from_input {
let inputted_file_number = INPUTTED_FILE_NUMBER.fetch_add(1, Ordering::SeqCst);
path = PathBuf::from(format!("Input/{}", inputted_file_number));
}
let content = content.unwrap_or_else(|err| {
eprintln!("{}: {}", path.display(), err);
process::exit(1);
});
(path, content)
})
.collect();
Ok(result)
}
fn get_content(path: &PathBuf, should_read_from_input: bool) -> Result<String> {
if should_read_from_input {
read_from_stdin()
} else {
let bars = MultiProgress::new();
let style =
ProgressStyle::with_template("[{elapsed}][{percent}%] {bar:45.cyan/blue} {bytes} {wide_msg}")?
.progress_chars(">-");
read_file_with_progress(path, style, bars)
}
}
fn read_file_with_progress(path: &PathBuf, style: ProgressStyle, bars: MultiProgress) -> Result<String> {
let mut content = String::new();
let file = File::open(path)?;
let size = file.metadata()?.len();
let bar = ProgressBar::new(size).with_message(format! {"Reading {}", path.display()}).with_style(style);
let bar = bars.add(bar);
let mut bufreader = BufReader::new(file);
let mut buf = [0; BUFFER_SIZR];
while let Ok(n) = bufreader.read(&mut buf) {
if n == 0 {
break;
}
bar.inc(n as u64);
content += &String::from_utf8_lossy(&buf[..n]);
}
bar.finish_with_message("Done!");
Ok(content)
}
fn read_from_stdin() -> Result<String> {
let mut content = vec![];
std::io::stdin().read_to_end(&mut content)?;
Ok(String::from_utf8(content)?)
}