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 #[deprecated(since = "0.2.2", note = "Use new_iter")]
31 pub fn iter(&self) -> Box<dyn Iterator<Item = InputFile>> {
32 match self {
33 Self::Dir(d) => Box::new(
34 fs::read_dir(d)
35 .ok()
36 .into_iter()
37 .flat_map(|rd| rd.filter_map(std::result::Result::ok))
38 .filter_map(|entry| {
39 let path = entry.path();
40 get_input_file_type(&path).map(|ty| InputFile {
41 ty,
42 path: path.into(),
43 })
44 }),
45 ),
46 Self::File(f) => Box::new(Some(f.clone()).into_iter()),
47 }
48 }
49
50 pub fn new_iter(&self) -> impl Iterator<Item = InputFile> + use<> {
53 match self {
54 Self::Dir(d) => Either::Left(
55 fs::read_dir(d)
56 .ok()
57 .into_iter()
58 .flat_map(|rd| rd.filter_map(std::result::Result::ok))
59 .filter_map(|entry| {
60 let path = entry.path();
61 get_input_file_type(&path).map(|ty| InputFile {
62 ty,
63 path: path.into(),
64 })
65 }),
66 ),
67 Self::File(f) => Either::Right(iter::once(f.clone())),
68 }
69 }
70}
71
72impl Input {
73 pub(crate) fn new(path: impl AsRef<Path>) -> Result<Input> {
74 let path = fs::canonicalize(path)?.into_boxed_path();
75
76 if path.is_dir() {
77 Ok(Self::Dir(path))
78 } else if let Some(ty) = get_input_file_type(&path) {
79 Ok(Self::File(InputFile { ty, path }))
80 } else {
81 Err("File has unsupported extension".into())
82 }
83 }
84}
85
86impl InputFileType {
87 pub(crate) const fn is_fb2(&self) -> bool {
88 matches!(self, Self::Fb2)
89 }
90
91 pub(crate) const fn is_fb2_zip(&self) -> bool {
92 matches!(self, Self::Fb2Zip)
93 }
94
95 pub(crate) const fn as_extension(&self) -> &'static str {
96 if self.is_fb2() { "fb2" } else { "fb2.zip" }
97 }
98}
99
100fn get_input_file_type(f: &Path) -> Option<InputFileType> {
101 let bytes = f.as_os_str().as_encoded_bytes();
102 let len = bytes.len();
103
104 for (ext, ty) in [
105 (".fb2", InputFileType::Fb2),
106 (".fb2.zip", InputFileType::Fb2Zip),
107 ] {
108 let ext = ext.as_bytes();
109 let l = ext.len();
110
111 if l > len {
112 break;
113 }
114 if bytes[len - l..len].eq_ignore_ascii_case(ext) {
115 return Some(ty);
116 }
117 }
118
119 None
120}