inky_frame/fs/volume/
iter.rs

1// Permission is hereby granted, free of charge, to any person obtaining a copy
2// of this software and associated documentation files (the "Software"), to deal
3// in the Software without restriction, including without limitation the rights
4// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5// copies of the Software, and to permit persons to whom the Software is
6// furnished to do so, subject to the following conditions:
7//
8// The above copyright notice and this permission notice shall be included in
9// all copies or substantial portions of the Software.
10//
11// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17// SOFTWARE.
18//
19
20#![no_implicit_prelude]
21
22extern crate core;
23
24use core::clone::Clone;
25use core::iter::{IntoIterator, Iterator};
26use core::marker::Copy;
27use core::ops::FnMut;
28use core::option::Option::{self, None, Some};
29use core::result::Result::{self, Err, Ok};
30
31use crate::fs::{Block, BlockCache, BlockDevice, BlockPtr, Cache, Cluster, DIR_SIZE, DeviceError, DirEntry, DirEntryFull, Directory, Volume};
32
33pub struct Range {
34    sel:   [RangeIndex; 0xA],
35    sum:   u8,
36    index: u8,
37}
38pub struct RangeIter {
39    cur:   RangeIndex,
40    range: Range,
41    pos:   u8,
42}
43pub struct RangeIndex(u32, u32, u32);
44pub struct DirectoryIndex<'a, B: BlockDevice> {
45    vol:     &'a Volume<'a, B>,
46    val:     DirEntryFull,
47    buf:     BlockPtr,
48    cache:   BlockCache,
49    entry:   u32,
50    block:   u32,
51    blocks:  u32,
52    cluster: u32,
53}
54pub struct DirectoryIter<'a, B: BlockDevice>(DirectoryIndex<'a, B>);
55pub struct DirectoryIterMut<'b, 'a: 'b, B: BlockDevice>(&'b mut DirectoryIndex<'a, B>);
56
57pub type RangeEntry = (u32, u32, bool, usize);
58
59impl Range {
60    #[inline]
61    pub(super) fn new() -> Range {
62        Range {
63            sel:   [const { RangeIndex::new() }; 0xA],
64            sum:   0u8,
65            index: 0u8,
66        }
67    }
68
69    #[inline(always)]
70    pub fn blocks(&self) -> u8 {
71        self.index
72    }
73
74    #[inline(always)]
75    pub(super) fn clear(&mut self) {
76        (self.sum, self.index) = (0u8, 0u8)
77    }
78    #[inline(always)]
79    pub(super) fn finish(&mut self, c: u32, b: u32, e: u32) {
80        self.sel[self.index as usize].set(c, b, e);
81    }
82    pub(super) fn mark(&mut self, c: u32, b: u32, e: u32) -> u8 {
83        if self.index == 0 {
84            self.sel[0].set(c, b, e);
85            (self.index, self.sum) = (1, 1);
86        } else {
87            let v = &mut self.sel[self.index as usize - 1];
88            if v.0 != c || v.1 != b {
89                self.sel[self.index as usize].set(c, b, e);
90                self.index += 1;
91            }
92            self.sum += 1;
93        }
94        self.sum
95    }
96}
97impl RangeIter {
98    fn is_next(&self) -> bool {
99        if self.cur.2 >= (Block::SIZE as u32 / DIR_SIZE as u32) {
100            return true;
101        }
102        if self.pos + 1 < self.range.index {
103            return false;
104        }
105        let v = self.range.sel[self.pos as usize + 1].2;
106        v == 0 || self.cur.2 > v
107    }
108    fn next_entry(&mut self) -> Option<RangeEntry> {
109        let n = if self.is_next() {
110            self.pos += 1;
111            if self.pos >= self.range.index {
112                return None;
113            }
114            self.cur = self.range.sel[self.pos as usize];
115            true
116        } else {
117            false || self.range.sel[self.pos as usize].2 == self.cur.2
118        };
119        let e = self.cur.2 as usize;
120        self.cur.2 += 1;
121        Some((self.cur.0, self.cur.1, n, e))
122    }
123}
124impl RangeIndex {
125    #[inline(always)]
126    const fn new() -> RangeIndex {
127        RangeIndex(0u32, 0u32, 0u32)
128    }
129
130    #[inline(always)]
131    fn set(&mut self, c: u32, b: u32, e: u32) {
132        (self.0, self.1, self.2) = (c, b, e);
133    }
134}
135impl<'b, 'a: 'b, B: BlockDevice> DirectoryIndex<'a, B> {
136    #[inline(always)]
137    pub(super) fn new(vol: &'a Volume<'a, B>) -> DirectoryIndex<'a, B> {
138        DirectoryIndex {
139            vol,
140            val: DirEntryFull::new(),
141            buf: Cache::block_b(),
142            cache: BlockCache::new(),
143            entry: 0u32,
144            block: 0u32,
145            blocks: 0u32,
146            cluster: 0u32,
147        }
148    }
149
150    /// This is the preferable function to use as it can be reset to save
151    /// space in memory.
152    #[inline(always)]
153    pub fn into_iter_mut(&'b mut self) -> DirectoryIterMut<'b, 'a, B> {
154        DirectoryIterMut(self)
155    }
156    #[inline(always)]
157    pub fn reset(&mut self, dir: &Directory<'a, B>) -> Result<(), DeviceError> {
158        self.setup(dir.cluster())
159    }
160    /// This function call cannot be "shortcut" stopped. Use "find" if stoppage
161    /// is needed.
162    #[inline]
163    pub fn iter(&mut self, mut func: impl FnMut(&DirEntryFull)) -> Result<(), DeviceError> {
164        loop {
165            match self.next(true)? {
166                Some(v) => func(v),
167                None => break,
168            }
169        }
170        Ok(())
171    }
172    #[inline]
173    pub fn find(&mut self, mut func: impl FnMut(&DirEntryFull) -> bool) -> Result<Option<DirEntry>, DeviceError> {
174        loop {
175            match self.next(true)? {
176                Some(v) if func(v) => return Ok(Some(v.entry())),
177                Some(_) => continue,
178                None => break,
179            }
180        }
181        Ok(None)
182    }
183
184    pub(super) fn setup(&mut self, start: Cluster) -> Result<(), DeviceError> {
185        self.entry = 0u32;
186        self.cache.clear();
187        self.cluster = start.unwrap_or_else(|| self.vol.man.root());
188        let i = self.vol.man.block_pos_at(self.cluster);
189        self.block = i;
190        self.blocks = i + self.vol.man.entries_count(start);
191        self.cache.read_single(self.vol.dev, &mut self.buf, i)?;
192        Ok(())
193    }
194
195    #[inline(always)]
196    fn is_loop_done(&self) -> bool {
197        self.entry >= (Block::SIZE / DIR_SIZE) as u32
198    }
199    fn is_complete(&mut self) -> Result<bool, DeviceError> {
200        if !self.is_loop_done() {
201            return Ok(false);
202        }
203        (self.entry, self.block) = (0, self.block + 1);
204        if self.block <= self.blocks {
205            return self
206                .cache
207                .read_single(self.vol.dev, &mut self.buf, self.block)
208                .map(|_| false);
209        }
210        self.cluster = match self
211            .vol
212            .man
213            .cluster_next(self.vol.dev, &mut self.buf, &mut self.cache, self.cluster)?
214        {
215            None => return Ok(true),
216            Some(v) => v,
217        };
218        let i = self.vol.man.block_pos_at(self.cluster);
219        (self.block, self.blocks) = (i, i + self.vol.man.blocks.blocks_per_cluster());
220        Ok(false)
221    }
222    fn next(&'b mut self, r: bool) -> Result<Option<&'b mut DirEntryFull>, DeviceError> {
223        if self.is_complete()? {
224            return Ok(None);
225        }
226        if r {
227            // NOTE(sf): If re-entrant (from user call) reset the LFN cache.
228            //           Since LFNs might span blocks.
229            self.val.reset();
230        }
231        while !self.is_loop_done() {
232            let s = self.entry as usize * DIR_SIZE;
233            if self.buf[s] == 0 {
234                return Ok(None);
235            }
236            self.entry += 1;
237            if self.buf[s + 0xB] & 0xF == 0xF {
238                self.val.fill(&self.buf[s..]);
239                continue;
240            }
241            if self.buf[s + 0xB] & 0x8 != 0 && self.buf[s + 0x1C] == 0 {
242                continue;
243            }
244            if self.buf[s] != 0xE5 {
245                self.val.load(&self.vol.man.ver, &self.buf[s..], self.block, s as u32);
246                // NOTE(sf): We're just returning a reference of the same struct.
247                //           Since the Iter trait won't allow lifetimes, this
248                //           is the next best thing. It should prevent the
249                //           pointer leaking out of scope.
250                return Ok(Some(&mut self.val));
251            }
252        }
253        self.next(false)
254    }
255}
256
257impl Copy for RangeIndex {}
258impl Clone for RangeIndex {
259    #[inline(always)]
260    fn clone(&self) -> RangeIndex {
261        RangeIndex(self.0, self.1, self.2)
262    }
263}
264
265impl Iterator for RangeIter {
266    type Item = RangeEntry;
267
268    #[inline(always)]
269    fn next(&mut self) -> Option<RangeEntry> {
270        self.next_entry()
271    }
272}
273
274impl Clone for Range {
275    #[inline(always)]
276    fn clone(&self) -> Range {
277        Range {
278            sel:   self.sel.clone(),
279            sum:   self.sum,
280            index: self.index,
281        }
282    }
283}
284impl IntoIterator for Range {
285    type Item = RangeEntry;
286    type IntoIter = RangeIter;
287
288    #[inline(always)]
289    fn into_iter(self) -> RangeIter {
290        RangeIter {
291            pos:   0u8,
292            cur:   self.sel[0],
293            range: self,
294        }
295    }
296}
297
298impl<'a, B: BlockDevice> IntoIterator for DirectoryIndex<'a, B> {
299    type IntoIter = DirectoryIter<'a, B>;
300    type Item = Result<DirEntry, DeviceError>;
301
302    #[inline(always)]
303    fn into_iter(self) -> DirectoryIter<'a, B> {
304        DirectoryIter(self)
305    }
306}
307impl<'b, 'a: 'b, B: BlockDevice> IntoIterator for &'b mut DirectoryIndex<'a, B> {
308    type IntoIter = DirectoryIterMut<'b, 'a, B>;
309    type Item = Result<DirEntry, DeviceError>;
310
311    #[inline(always)]
312    fn into_iter(self) -> DirectoryIterMut<'b, 'a, B> {
313        DirectoryIterMut(self)
314    }
315}
316
317impl<'a, B: BlockDevice> Iterator for DirectoryIter<'a, B> {
318    type Item = Result<DirEntry, DeviceError>;
319
320    #[inline]
321    fn next(&mut self) -> Option<Result<DirEntry, DeviceError>> {
322        match self.0.next(true) {
323            Ok(None) => None,
324            Ok(Some(v)) => Some(Ok(v.entry())),
325            Err(e) => Some(Err(e)),
326        }
327    }
328}
329
330impl<'b, 'a: 'b, B: BlockDevice> Iterator for DirectoryIterMut<'b, 'a, B> {
331    type Item = Result<DirEntry, DeviceError>;
332
333    #[inline]
334    fn next(&mut self) -> Option<Result<DirEntry, DeviceError>> {
335        match self.0.next(true) {
336            Ok(None) => None,
337            Ok(Some(v)) => Some(Ok(v.entry())),
338            Err(e) => Some(Err(e)),
339        }
340    }
341}