file_matcher/entries/
one.rs1use crate::utils::is_readable_entry;
2use crate::{EntryName, EntryType, FileMatcherError, Result};
3use std::ffi::OsString;
4use std::fmt::Debug;
5use std::io::Read;
6use std::path::{Path, PathBuf};
7
8pub trait OneEntryNamed: Debug {
9 fn within_path_buf(&self, directory: PathBuf) -> OneEntry;
10 fn entry_name(&self) -> &EntryName;
11 fn entry_type(&self) -> &EntryType;
12 fn name_alias(&self) -> Option<&str>;
13 fn boxed(&self) -> Box<dyn OneEntryNamed>;
14}
15
16#[derive(Debug)]
17pub struct OneEntry {
18 entry_named: Box<dyn OneEntryNamed>,
19 directory: PathBuf,
20}
21
22impl OneEntry {
23 pub fn new(entry_named: Box<dyn OneEntryNamed>, directory: impl Into<PathBuf>) -> Self {
24 Self {
25 entry_named,
26 directory: directory.into(),
27 }
28 }
29
30 pub fn entry(&self) -> &dyn OneEntryNamed {
31 self.entry_named.as_ref()
32 }
33
34 pub fn entry_type(&self) -> &EntryType {
35 self.entry().entry_type()
36 }
37
38 pub fn entry_name(&self) -> &EntryName {
39 self.entry().entry_name()
40 }
41
42 pub fn directory(&self) -> &Path {
43 self.directory.as_path()
44 }
45
46 pub fn exists(&self) -> Result<bool> {
49 match self.find() {
50 Ok(path) => Ok(path.exists()),
51 Err(error) => match &error {
52 FileMatcherError::NotExists(_) => Ok(false),
53 _ => error.into(),
54 },
55 }
56 }
57
58 pub fn find(&self) -> Result<PathBuf> {
60 let entry_type = self.entry_named.entry_type();
61 let entry_name = self.entry_named.entry_name();
62
63 self.find_by_type_and_name(entry_type, entry_name)
64 }
65
66 fn find_by_type_and_name(
67 &self,
68 entry_type: &EntryType,
69 entry_name: &EntryName,
70 ) -> Result<PathBuf> {
71 match entry_name {
72 EntryName::Exact(name) => {
73 let entry = self.directory.join(name);
74 if is_readable_entry(entry_type, &entry) {
75 Ok(entry)
76 } else {
77 FileMatcherError::NotExists(self.clone()).into()
78 }
79 }
80 EntryName::Any(names) => {
81 let entries = names
82 .iter()
83 .map(|each| self.directory.join(each))
84 .filter(|each| is_readable_entry(entry_type, each.as_path()))
85 .collect::<Vec<PathBuf>>();
86
87 match entries.len() {
88 0 => FileMatcherError::NotExists(self.clone()).into(),
89 1 => Ok(entries.first().unwrap().to_owned()),
90 _ => FileMatcherError::TooMany(self.clone()).into(),
91 }
92 }
93 EntryName::AnyNamed(entry_names) => {
94 let mut entries: Vec<PathBuf> = vec![];
95
96 for entry_name in entry_names {
97 (match self.find_by_type_and_name(entry_type, entry_name) {
98 Ok(entry) => {
99 entries.push(entry);
100 Ok(())
101 }
102 Err(error) => match &error {
103 FileMatcherError::NotExists(_) => Ok(()),
104 _ => error.into(),
105 },
106 })?;
107 }
108
109 match entries.len() {
110 0 => FileMatcherError::NotExists(self.clone()).into(),
111 1 => Ok(entries.first().unwrap().to_owned()),
112 _ => FileMatcherError::TooMany(self.clone()).into(),
113 }
114 }
115 #[cfg(feature = "regex")]
116 EntryName::Regex(regex_pattern) => {
117 let entries = crate::finders::regex_finder::find_entries_in_directory_matching(
118 entry_type,
119 regex_pattern,
120 &self.directory,
121 )?;
122 match entries.len() {
123 0 => FileMatcherError::NotExists(self.clone()).into(),
124 1 => Ok(entries.first().unwrap().to_owned()),
125 _ => FileMatcherError::TooMany(self.clone()).into(),
126 }
127 }
128 #[cfg(feature = "wildmatch")]
129 EntryName::Wildmatch(wildmatch_pattern) => {
130 let entries = crate::finders::wildmatch_finder::find_entries_in_directory_matching(
131 entry_type,
132 wildmatch_pattern,
133 &self.directory,
134 )?;
135 match entries.len() {
136 0 => FileMatcherError::NotExists(self.clone()).into(),
137 1 => Ok(entries.first().unwrap().to_owned()),
138 _ => FileMatcherError::TooMany(self.clone()).into(),
139 }
140 }
141 }
142 }
143
144 pub fn as_path_buf(&self) -> Result<PathBuf> {
145 self.find()
146 }
147
148 pub fn as_os_string(&self) -> Result<OsString> {
149 let path = self.find()?;
150 match path.file_name() {
151 None => FileMatcherError::NotReadable(path.clone()).into(),
152 Some(file_name) => Ok(file_name.to_os_string()),
153 }
154 }
155
156 pub fn as_string(&self) -> Result<String> {
157 let file_name = self.as_os_string()?;
158 match file_name.to_str() {
159 None => FileMatcherError::InvalidUnicode(file_name).into(),
160 Some(file_name) => Ok(file_name.to_owned()),
161 }
162 }
163
164 pub fn as_bytes(&self) -> Result<Vec<u8>> {
165 let path = self.find()?;
166 let mut file = std::fs::File::open(path.as_path())?;
167 let mut buffer = Vec::new();
168 file.read_to_end(&mut buffer)?;
169 Ok(buffer)
170 }
171}
172
173impl Clone for OneEntry {
174 fn clone(&self) -> Self {
175 Self::new(self.entry_named.boxed(), self.directory.clone())
176 }
177}
178
179impl From<OneEntry> for PathBuf {
180 fn from(filter: OneEntry) -> Self {
181 PathBuf::from(&filter)
182 }
183}
184
185impl From<&OneEntry> for PathBuf {
186 fn from(filter: &OneEntry) -> Self {
187 filter
188 .find()
189 .expect("Could not find exactly one matching file")
190 }
191}
192
193impl From<&OneEntry> for Result<OsString> {
194 fn from(filter: &OneEntry) -> Self {
195 filter.as_os_string()
196 }
197}
198
199impl From<OneEntry> for Result<OsString> {
200 fn from(filter: OneEntry) -> Self {
201 (&filter).into()
202 }
203}
204
205impl From<&OneEntry> for Result<String> {
206 fn from(filter: &OneEntry) -> Self {
207 filter.as_string()
208 }
209}
210
211impl From<OneEntry> for Result<String> {
212 fn from(filter: OneEntry) -> Self {
213 (&filter).into()
214 }
215}
216
217impl From<&OneEntry> for Result<Vec<u8>> {
218 fn from(filter: &OneEntry) -> Self {
219 filter.as_bytes()
220 }
221}
222
223impl From<OneEntry> for Result<Vec<u8>> {
224 fn from(filter: OneEntry) -> Self {
225 (&filter).into()
226 }
227}