mini_fs/
store.rs

1use std::collections::btree_set::BTreeSet;
2use std::ffi::OsString;
3use std::io;
4use std::path::Path;
5
6/// File or directory entry.
7#[derive(Debug, Clone, Eq, PartialEq)]
8pub struct Entry {
9    pub name: OsString,
10    pub kind: EntryKind,
11}
12
13/// Type of file entry.
14#[derive(Debug, Clone, Copy, Eq, PartialEq)]
15pub enum EntryKind {
16    File,
17    Dir,
18    /*TODO symlinks
19     *Sym, */
20}
21
22/// Iterator of file entries.
23pub struct Entries<'a> {
24    inner: Box<dyn Iterator<Item = io::Result<Entry>> + 'a>,
25}
26
27impl<'a> Entries<'a> {
28    pub fn new<I>(iter: I) -> Self
29    where
30        I: IntoIterator<Item = <Entries<'a> as Iterator>::Item>,
31        <I as IntoIterator>::IntoIter: 'a,
32    {
33        Self {
34            inner: Box::new(iter.into_iter()),
35        }
36    }
37}
38
39impl Iterator for Entries<'_> {
40    type Item = io::Result<Entry>;
41
42    fn next(&mut self) -> Option<Self::Item> {
43        self.inner.next()
44    }
45}
46
47/// Generic file storage.
48pub trait Store {
49    type File;
50
51    fn open_path(&self, path: &Path) -> io::Result<Self::File>;
52
53    /// Returns an iterator over the files & directory entries in a given path.
54    fn entries_path(&self, _: &Path) -> io::Result<Entries> {
55        unimplemented!("entries_path is not implemented.")
56    }
57}
58
59/// Convenient methods on top of Store.
60pub trait StoreExt: Store {
61    fn entries<P: AsRef<Path>>(&self, path: P) -> io::Result<Entries> {
62        <Self as Store>::entries_path(self, &crate::index::normalize_path(path.as_ref()))
63    }
64
65    fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<Self::File> {
66        <Self as Store>::open_path(self, &crate::index::normalize_path(path.as_ref()))
67    }
68}
69
70impl<T: Store> StoreExt for T {}
71
72pub(crate) struct MapFile<S, F> {
73    store: S,
74    clo: F,
75}
76
77impl<S, F> MapFile<S, F> {
78    pub(crate) fn new(store: S, closure: F) -> Self {
79        Self {
80            store,
81            clo: closure,
82        }
83    }
84}
85
86impl<U, S, F> Store for MapFile<S, F>
87where
88    S: Store,
89    F: Fn(S::File) -> U,
90{
91    type File = U;
92    #[inline]
93    fn open_path(&self, path: &Path) -> io::Result<Self::File> {
94        match self.store.open_path(path) {
95            Ok(file) => Ok((self.clo)(file)),
96            Err(err) => Err(err),
97        }
98    }
99
100    #[inline]
101    fn entries_path(&self, path: &Path) -> io::Result<Entries> {
102        self.store.entries_path(path)
103    }
104}
105
106// iterator + set to take care of repeating elements.
107// TODO consider other data structures for the set.
108struct TupleEntries<I> {
109    inner: I,
110    set: BTreeSet<OsString>,
111}
112
113impl<I> TupleEntries<I> {
114    fn new(inner: I) -> Self {
115        Self {
116            inner,
117            set: BTreeSet::new(),
118        }
119    }
120}
121
122impl<I> Iterator for TupleEntries<I>
123where
124    I: Iterator<Item = io::Result<Entry>>,
125{
126    type Item = <I as Iterator>::Item;
127    fn next(&mut self) -> Option<Self::Item> {
128        loop {
129            match self.inner.next() {
130                None => return None,
131                Some(Err(e)) => return Some(Err(e)),
132                Some(Ok(file)) => {
133                    if self.set.insert(file.name.clone()) {
134                        return Some(Ok(file));
135                    }
136                }
137            }
138        }
139    }
140}
141
142// Implement tuples of up to 11 elements (12 or more looks bad on the rustdoc)
143store_tuples! { A, B, C, D, E, F, G, H, I, J, K, }