1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use std::convert::TryInto;

use crate::{extension, extension::Iter, util::from_be_u32};

impl<'a> Iter<'a> {
    /// Create a new extension iterator at the entrypoint for extensions until the end of the extensions.
    pub fn new(data_at_beginning_of_extensions_and_truncated: &'a [u8]) -> Self {
        Iter {
            data: data_at_beginning_of_extensions_and_truncated,
            consumed: 0,
        }
    }

    /// Create a new iterator at with a data block to the end of the file, and we automatically remove the trailing
    /// hash of type `object_hash`.
    pub fn new_without_checksum(
        data_at_beginning_of_extensions: &'a [u8],
        object_hash: gix_hash::Kind,
    ) -> Option<Self> {
        let end = data_at_beginning_of_extensions
            .len()
            .checked_sub(object_hash.len_in_bytes())?;
        Iter {
            data: &data_at_beginning_of_extensions[..end],
            consumed: 0,
        }
        .into()
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = (extension::Signature, &'a [u8]);

    fn next(&mut self) -> Option<Self::Item> {
        if self.data.len() < 4 + 4 {
            return None;
        }

        let (signature, data) = self.data.split_at(4);
        let (size, data) = data.split_at(4);
        self.data = data;
        self.consumed += 4 + 4;

        let size = from_be_u32(size) as usize;

        match data.get(..size) {
            Some(ext_data) => {
                self.data = &data[size..];
                self.consumed += size;
                Some((signature.try_into().unwrap(), ext_data))
            }
            None => {
                self.data = &[];
                None
            }
        }
    }
}