the_lock_lib/
directory_content.rs

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    // Dead code
295    #[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    // Dead code
317    #[cfg(test)]
318    pub(crate) fn add_file(&mut self, path: &DirectoryContentPath) -> DirectoryContentResult<&mut SingleEncryptedFile> {
319        self._add_file(path.into())
320    }
321
322    // Dead code
323    #[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()]); // TODO delete useless copying
368                    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 self, path: &str) -> DirectoryContentResult<&SingleEncryptedFile> {
380    //     if self.get_file(path).is_some() {
381    //         Ok(self.get_file(path).unwrap())
382    //     }
383    //     else {
384    //         let x: &SingleEncryptedFile = self.add_file_with_path(path)?;
385    //         Ok(x)
386    //     }
387    //     // todo!("Optimize it somehow")
388    // }
389
390    pub(crate) fn get_or_create_file_mut(&mut self, path: &DirectoryContentPath) -> DirectoryContentResult<&mut SingleEncryptedFile> {
391        // {
392        //     if let Some(ans) = self.get_file_mut(path) {
393        //         return Ok(ans);
394        //     }
395        // }
396        // self.add_file_with_path(path)
397
398        // One of those should work
399
400        // match self.get_file_mut(path) {
401        //     Some(ans) => Ok(ans),
402        //     None => self.add_file_with_path(path),
403        // }
404
405        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        // todo!("Optimize it somehow - borrow checker does its best to stop me")
412    }
413
414    // pub(crate) fn get_or_create_dir(&mut self, path: &str) -> DirectoryContentResult<&DirectoryContent> {
415    //     if self.get_dir(path).is_some() {
416    //         Ok(self.get_dir(path).unwrap())
417    //     }
418    //     else {
419    //         let x: &DirectoryContent = self.add_directory(path)?;
420    //         Ok(x)
421    //     }
422    //     // todo!("Optimize it somehow")
423    // }
424
425    // pub(crate) fn get_or_create_dir_mut(&mut self, path: &str) -> DirectoryContentResult<&mut DirectoryContent> {
426    //     if self.get_dir(path).is_some() {
427    //         Ok(self.get_dir_mut(path).unwrap())
428    //     }
429    //     else {
430    //         Ok(self.add_directory(path)?)
431    //     }
432    //     // todo!("Optimize it somehow")
433    // }
434
435    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(crate) fn get_files_iter_mut(&mut self) -> IterMut<String, SingleEncryptedFile> {
444    //     self.files.iter_mut()
445    // }
446
447    // pub(crate) fn get_dir_iter_mut(&mut self) -> IterMut<String, DirectoryContent> {
448    //     self.directories.iter_mut()
449    // }
450
451    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}