1use std::collections::{BTreeMap, btree_map::Iter};
2
3#[cfg(feature = "serde")]
4use serde::{Serialize, Deserialize};
5
6use crate::error::{ContentError, DirectoryContentResult, DirectoryContentPathResult, DirectoryContentPathError};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct DirectoryContentPath(Vec<String>);
10
11impl Default for DirectoryContentPath {
12 fn default() -> Self {
13 Self(Vec::new())
14 }
15}
16
17impl DirectoryContentPath {
18 fn verify(s: &str) -> DirectoryContentPathResult<String> {
19 let mut ans = String::with_capacity(s.len());
20 for c in s.trim().chars() {
21 if !c.is_ascii() || c.is_ascii_control() || c == '/' || c == '\\' {
22 continue;
23 }
24 ans.push(c);
25 }
26 if ans.is_empty() {
27 return Err(DirectoryContentPathError::ElementCannotBeEmpty);
28 }
29 Ok(ans)
30 }
31
32 pub fn file_name(&self) -> Option<&str> {
33 self.0.last().map(|v| v.as_str())
34 }
35
36 pub fn push(&mut self, element: &str) -> DirectoryContentPathResult<()> {
37 self.0.push(Self::verify(element)?);
38 Ok(())
39 }
40
41 pub fn len(&self) -> usize {
42 self.0.len()
43 }
44
45 pub fn root(&self) -> Option<&str> {
46 self.0.first().map(|v| v.as_str())
47 }
48
49 pub fn get(&self, n: usize) -> Option<&str> {
50 self.0.get(n).map(|v| v.as_str())
51 }
52
53 pub fn append(&mut self, mut other: Self) {
54 self.0.append(&mut other.0);
55 }
56
57 pub fn pop(&mut self) -> Option<String> {
58 self.0.pop()
59 }
60
61 pub fn iter(&self) -> std::slice::Iter<'_, String> {
62 self.into_iter()
63 }
64}
65
66impl<'a> Into<&'a [String]> for &'a DirectoryContentPath {
67 fn into(self) -> &'a [String] {
68 self.0.as_slice()
69 }
70}
71
72impl std::fmt::Display for DirectoryContentPath {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 write!(f, "{}", {
75 let mut ans = String::new();
76 if let Some(first) = self.0.first() {
77 ans.push_str(first);
78 }
79 for path in self.0.iter().skip(1) {
80 ans.push('/');
81 ans.push_str(path);
82 }
83 ans
84 })
85 }
86}
87
88impl From<String> for DirectoryContentPath {
89 fn from(value: String) -> Self {
90 Self::from(value.as_str())
91 }
92}
93
94impl From<&str> for DirectoryContentPath {
95 fn from(value: &str) -> Self {
96 let mut ans = Self::default();
97 let mut next = String::new();
98 for c in value.chars() {
99 if c == '/' || c == '\\' {
100 if !next.is_empty() {
101 let _ = ans.push(&next);
102 next.clear();
103 }
104 continue;
105 }
106 next.push(c);
107 }
108 if !next.is_empty() {
109 let _ = ans.push(&next);
110 }
111 ans
112 }
113}
114
115impl IntoIterator for DirectoryContentPath {
116 type IntoIter = std::vec::IntoIter<String>;
117 type Item = String;
118
119 fn into_iter(self) -> Self::IntoIter {
120 self.0.into_iter()
121 }
122}
123
124impl<'a> IntoIterator for &'a DirectoryContentPath {
125 type IntoIter = std::slice::Iter<'a, String>;
126 type Item = &'a String;
127
128 fn into_iter(self) -> Self::IntoIter {
129 self.0.iter()
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
134#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
135pub struct SingleEncryptedFile {
136 has_content: bool,
137 has_key: bool,
138 is_signed: bool,
139 has_digest: bool,
140}
141
142impl Default for SingleEncryptedFile {
143 #[inline]
144 fn default() -> Self {
145 Self { has_content: false, has_key: false, is_signed: false, has_digest: false }
146 }
147}
148
149impl SingleEncryptedFile {
150 #[inline]
151 pub fn new() -> Self {
152 Self::default()
153 }
154
155 #[inline]
156 pub fn new_with_val(has_content: bool, has_key: bool, is_signed: bool, has_digest: bool) -> Self {
157 Self { has_content, has_key, is_signed, has_digest }
158 }
159
160 #[inline]
161 pub fn content(&mut self, content: bool) -> &mut Self {
162 self.has_content = content;
163 self
164 }
165
166 #[inline]
167 pub fn has_content(&self) -> bool {
168 self.has_content
169 }
170
171 #[inline]
172 pub fn key(&mut self, key: bool) -> &mut Self {
173 self.has_key = key;
174 self
175 }
176
177 #[inline]
178 pub fn has_key(&self) -> bool {
179 self.has_key
180 }
181
182 #[inline]
183 pub fn signed(&mut self, v: bool) -> &mut Self {
184 self.is_signed = v;
185 self
186 }
187
188 #[inline]
189 pub fn is_signed(&self) -> bool {
190 self.is_signed
191 }
192
193 #[inline]
194 pub fn digest(&mut self, v: bool) -> &mut Self {
195 self.has_digest = v;
196 self
197 }
198
199 #[inline]
200 pub fn has_digest(&self) -> bool {
201 self.has_digest
202 }
203}
204
205#[derive(Debug, Clone, PartialEq, Eq)]
206#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
207pub struct DirectoryContent {
208 files: BTreeMap<String, SingleEncryptedFile>,
209 directories: BTreeMap<String, DirectoryContent>,
210 total_file_count: usize,
211}
212
213impl Default for DirectoryContent {
214 #[inline]
215 fn default() -> Self {
216 Self { files: BTreeMap::new(), directories: BTreeMap::new(), total_file_count: 0 }
217 }
218}
219
220impl DirectoryContent {
221 #[inline]
222 pub fn new() -> Self {
223 Self::default()
224 }
225
226 pub fn get_dir(&self, path: &DirectoryContentPath) -> Option<&DirectoryContent> {
227 self._get_dir(path.into())
228 }
229
230 fn _get_dir(&self, path: &[String]) -> Option<&DirectoryContent> {
231 if let Some(next_part) = path.first() {
232 match (path.len() == 1, self.directories.get(next_part)) {
233 (true, Some(dir)) => Some(dir),
234 (false, Some(dir)) => dir._get_dir(path.get(1..).expect("Check if size is >= 1")),
235 (_, None) => None,
236 }
237 }
238 else {
239 Some(self)
240 }
241 }
242
243 pub fn get_dir_mut(&mut self, path: &DirectoryContentPath) -> Option<&mut DirectoryContent> {
244 self._get_dir_mut(path.into())
245 }
246
247 fn _get_dir_mut(&mut self, path: &[String]) -> Option<&mut DirectoryContent> {
248 if let Some(next_part) = path.first() {
249 match (path.len() == 1, self.directories.get_mut(next_part)) {
250 (true, Some(dir)) => Some(dir),
251 (false, Some(dir)) => dir._get_dir_mut(path.get(1..).expect("Check if size is >= 1")),
252 (_, None) => None,
253 }
254 }
255 else {
256 Some(self)
257 }
258 }
259
260 pub fn get_file(&self, path: &DirectoryContentPath) -> Option<&SingleEncryptedFile> {
261 self._get_file(path.into())
262 }
263
264 fn _get_file(&self, path: &[String]) -> Option<&SingleEncryptedFile> {
265 if let Some(next_part) = path.first() {
266 match (path.len() == 1, self.files.get(next_part), self.directories.get(next_part)) {
267 (true, Some(file), _) => Some(file),
268 (false, _, Some(dir)) => dir._get_file(path.get(1..).expect("Check if size is > 1")),
269 _ => None,
270 }
271 }
272 else {
273 None
274 }
275 }
276
277 pub(crate) fn get_file_mut(&mut self, path: &DirectoryContentPath) -> Option<&mut SingleEncryptedFile> {
278 self._get_file_mut(path.into())
279 }
280
281 fn _get_file_mut(&mut self, path: &[String]) -> Option<&mut SingleEncryptedFile> {
282 if let Some(next_part) = path.first() {
283 match (path.len() == 1, self.files.get_mut(next_part), self.directories.get_mut(next_part)) {
284 (true, Some(file), _) => Some(file),
285 (false, _, Some(dir)) => dir._get_file_mut(path.get(1..).expect("Check if size is > 1")),
286 _ => None,
287 }
288 }
289 else {
290 None
291 }
292 }
293
294 #[cfg(test)]
296 pub(crate) fn add_directory(&mut self, path: &DirectoryContentPath) -> DirectoryContentResult<&mut DirectoryContent> {
297 self._add_directory(path.into())
298 }
299
300 fn _add_directory(&mut self, path: &[String]) -> DirectoryContentResult<&mut DirectoryContent> {
301 if let Some(next_part) = path.first() {
302 match (self.files.contains_key(next_part), self.directories.contains_key(next_part)) {
303 (_, true) => self.directories.get_mut(next_part).unwrap()._add_directory(path.get(1..).expect("Check if size is >= 1")),
304 (false, false) => {
305 self.directories.insert(next_part.to_owned(), DirectoryContent::new());
306 self.directories.get_mut(next_part).unwrap()._add_directory(path.get(1..).expect("Check if size is >= 1"))
307 },
308 (true, false) => Err(ContentError::FileAlreadyExists),
309 }
310 }
311 else {
312 Ok(self)
313 }
314 }
315
316 #[cfg(test)]
318 pub(crate) fn add_file(&mut self, path: &DirectoryContentPath) -> DirectoryContentResult<&mut SingleEncryptedFile> {
319 self._add_file(path.into())
320 }
321
322 #[cfg(test)]
324 fn _add_file(&mut self, path: &[String]) -> DirectoryContentResult<&mut SingleEncryptedFile> {
325 if let Some(next_part) = path.first() {
326 match (path.len() == 1, self.files.contains_key(next_part), self.directories.contains_key(next_part)) {
327 (true, false, false) => {
328 self.files.insert(next_part.to_owned(), SingleEncryptedFile::new());
329 self.total_file_count += 1;
330 Ok(self.files.get_mut(next_part).unwrap())
331 },
332 (false, _, true) => {
333 let ans = self.directories.get_mut(next_part).unwrap()._add_file(path.get(1..).expect("Check if size is >= 1"));
334 self.total_file_count += ans.is_ok() as usize;
335 ans
336 }
337 (true, _, true) => Err(ContentError::DirectoryAlreadyExists),
338 (true, true, false) => Err(ContentError::FileAlreadyExists),
339 (false, _, false) => Err(ContentError::DirectoryDoesNotExist),
340 }
341 }
342 else {
343 Err(ContentError::NameCanNotBeEmpty)
344 }
345 }
346
347 pub(crate) fn add_file_with_path(&mut self, path: &DirectoryContentPath) -> DirectoryContentResult<&mut SingleEncryptedFile> {
348 self._add_file_with_path(path.into())
349 }
350
351 fn _add_file_with_path(&mut self, path: &[String]) -> DirectoryContentResult<&mut SingleEncryptedFile> {
352 if let Some(next_part) = path.first() {
353 match (path.len() == 1, self.files.contains_key(next_part), self.directories.contains_key(next_part)) {
354 (true, false, false) => {
355 self.files.insert(next_part.to_owned(), SingleEncryptedFile::new());
356 self.total_file_count += 1;
357 Ok(self.files.get_mut(next_part).unwrap())
358 },
359 (false, _, true) => {
360 let ans = self.directories.get_mut(next_part).unwrap()._add_file_with_path(path.get(1..).expect("Check if size is > 1"));
361 self.total_file_count += ans.is_ok() as usize;
362 ans
363 }
364 (true, _, true) => Err(ContentError::DirectoryAlreadyExists),
365 (true, true, false) => Err(ContentError::FileAlreadyExists),
366 (false, _, false) => {
367 let _ = self._add_directory(&[next_part.to_owned()]); let ans = self.directories.get_mut(next_part).unwrap()._add_file_with_path(path.get(1..).expect("Check if size is > 1"));
369 self.total_file_count += ans.is_ok() as usize;
370 ans
371 }
372 }
373 }
374 else {
375 Err(ContentError::NameCanNotBeEmpty)
376 }
377 }
378
379 pub(crate) fn get_or_create_file_mut(&mut self, path: &DirectoryContentPath) -> DirectoryContentResult<&mut SingleEncryptedFile> {
391 if self.get_file(path).is_some() {
406 Ok(self.get_file_mut(path).unwrap())
407 }
408 else {
409 self.add_file_with_path(path)
410 }
411 }
413
414 pub fn get_files_iter(&self) -> Iter<String, SingleEncryptedFile> {
436 self.files.iter()
437 }
438
439 pub fn get_dir_iter(&self) -> Iter<String, DirectoryContent> {
440 self.directories.iter()
441 }
442
443 pub fn exists(&self, path: &DirectoryContentPath) -> bool {
452 self._exists(path.into())
453 }
454
455 pub fn _exists(&self, path: &[String]) -> bool {
456 if let Some(next_part) = path.first() {
457 match (path.len() == 1, self.files.get(next_part), self.directories.get(next_part)) {
458 (true, Some(_), _) | (true, None, Some(_)) => true,
459 (false, _, Some(dir)) => dir._exists(path.get(1..).expect("Check if len is >= 1")),
460 _ => false,
461 }
462 }
463 else {
464 true
465 }
466 }
467
468 #[inline]
469 pub fn get_total_file_count(&self) -> usize {
470 self.total_file_count
471 }
472}