fb2_clean/config/
input.rs1use crate::Result;
2use either::Either;
3use std::{fs, iter, path::Path};
4
5#[derive(Clone, Debug, PartialEq)]
7pub enum Input {
8 Dir(Box<Path>),
9 File(InputFile),
10}
11
12#[derive(Clone, Debug, Hash, Eq, PartialEq)]
14pub struct InputFile {
15 pub ty: InputFileType,
16 pub path: Box<Path>,
17}
18
19#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
21#[non_exhaustive]
22pub enum InputFileType {
23 Fb2,
24 Fb2Zip,
25}
26
27impl Input {
28 pub fn iter(&self) -> impl Iterator<Item = InputFile> + use<> {
31 match self {
32 Self::Dir(d) => Either::Left(
33 fs::read_dir(d)
34 .ok()
35 .into_iter()
36 .flat_map(|rd| rd.filter_map(std::result::Result::ok))
37 .filter_map(|entry| {
38 let path = entry.path();
39 get_input_file_type(&path).map(|ty| InputFile {
40 ty,
41 path: path.into(),
42 })
43 }),
44 ),
45 Self::File(f) => Either::Right(iter::once(f.clone())),
46 }
47 }
48}
49
50impl Default for Input {
51 fn default() -> Input {
52 Input::new(".").unwrap_or_else(|_| Input::Dir(Path::new(".").into()))
53 }
54}
55
56impl Input {
57 pub(crate) fn new(path: impl AsRef<Path>) -> Result<Input> {
58 let path = fs::canonicalize(path)?.into_boxed_path();
59
60 if path.is_dir() {
61 Ok(Self::Dir(path))
62 } else if let Some(ty) = get_input_file_type(&path) {
63 Ok(Self::File(InputFile { ty, path }))
64 } else {
65 Err("File has unsupported extension".into())
66 }
67 }
68}
69
70impl InputFileType {
71 pub(crate) const fn is_fb2(&self) -> bool {
72 matches!(self, Self::Fb2)
73 }
74
75 pub(crate) const fn is_fb2_zip(&self) -> bool {
76 matches!(self, Self::Fb2Zip)
77 }
78
79 pub(crate) const fn as_extension(&self) -> &'static str {
80 if self.is_fb2() { "fb2" } else { "fb2.zip" }
81 }
82}
83
84fn get_input_file_type(f: &Path) -> Option<InputFileType> {
85 let bytes = f.as_os_str().as_encoded_bytes();
86 let len = bytes.len();
87
88 for (ext, ty) in [
89 (".fb2", InputFileType::Fb2),
90 (".fb2.zip", InputFileType::Fb2Zip),
91 ] {
92 let ext = ext.as_bytes();
93 let l = ext.len();
94
95 if l > len {
96 break;
97 }
98 if bytes[len - l..len].eq_ignore_ascii_case(ext) {
99 return Some(ty);
100 }
101 }
102
103 None
104}