summaryrefslogtreecommitdiffstats
path: root/vendor/gix-object/src/tree/ref_iter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-object/src/tree/ref_iter.rs')
-rw-r--r--vendor/gix-object/src/tree/ref_iter.rs115
1 files changed, 53 insertions, 62 deletions
diff --git a/vendor/gix-object/src/tree/ref_iter.rs b/vendor/gix-object/src/tree/ref_iter.rs
index be1244910..bc953ff4d 100644
--- a/vendor/gix-object/src/tree/ref_iter.rs
+++ b/vendor/gix-object/src/tree/ref_iter.rs
@@ -1,7 +1,7 @@
use std::convert::TryFrom;
use bstr::BStr;
-use winnow::error::ParserError;
+use winnow::{error::ParserError, prelude::*};
use crate::{tree, tree::EntryRef, TreeRef, TreeRefIter};
@@ -15,7 +15,11 @@ impl<'a> TreeRefIter<'a> {
impl<'a> TreeRef<'a> {
/// Deserialize a Tree from `data`.
pub fn from_bytes(mut data: &'a [u8]) -> Result<TreeRef<'a>, crate::decode::Error> {
- decode::tree(&mut data).map_err(crate::decode::Error::with_err)
+ let input = &mut data;
+ match decode::tree.parse_next(input) {
+ Ok(tag) => Ok(tag),
+ Err(err) => Err(crate::decode::Error::with_err(err, input)),
+ }
}
/// Find an entry named `name` knowing if the entry is a directory or not, using a binary search.
@@ -26,10 +30,11 @@ impl<'a> TreeRef<'a> {
let search = EntryRef {
mode: if is_dir {
- tree::EntryMode::Tree
+ tree::EntryKind::Tree
} else {
- tree::EntryMode::Blob
- },
+ tree::EntryKind::Blob
+ }
+ .into(),
filename: name,
oid: &NULL_HASH,
};
@@ -67,11 +72,12 @@ impl<'a> Iterator for TreeRefIter<'a> {
Some(Ok(entry))
}
None => {
+ let failing = self.data;
self.data = &[];
- let empty = &[] as &[u8];
#[allow(clippy::unit_arg)]
Some(Err(crate::decode::Error::with_err(
- winnow::error::ErrMode::from_error_kind(&empty, winnow::error::ErrorKind::Verify),
+ winnow::error::ErrMode::from_error_kind(&failing, winnow::error::ErrorKind::Verify),
+ failing,
)))
}
}
@@ -82,31 +88,33 @@ impl<'a> TryFrom<&'a [u8]> for tree::EntryMode {
type Error = &'a [u8];
fn try_from(mode: &'a [u8]) -> Result<Self, Self::Error> {
- Ok(match mode {
- b"40000" => tree::EntryMode::Tree,
- b"100644" => tree::EntryMode::Blob,
- b"100755" => tree::EntryMode::BlobExecutable,
- b"120000" => tree::EntryMode::Link,
- b"160000" => tree::EntryMode::Commit,
- b"100664" => tree::EntryMode::Blob, // rare and found in the linux kernel
- b"100640" => tree::EntryMode::Blob, // rare and found in the Rust repo
- _ => return Err(mode),
- })
+ mode_from_decimal(mode)
+ .map(|(mode, _rest)| tree::EntryMode(mode as u16))
+ .ok_or(mode)
}
}
+fn mode_from_decimal(i: &[u8]) -> Option<(u32, &[u8])> {
+ let mut mode = 0u32;
+ let mut spacer_pos = 1;
+ for b in i.iter().take_while(|b| **b != b' ') {
+ if *b < b'0' || *b > b'7' {
+ return None;
+ }
+ mode = (mode << 3) + (b - b'0') as u32;
+ spacer_pos += 1;
+ }
+ let (_, i) = i.split_at(spacer_pos);
+ Some((mode, i))
+}
+
impl TryFrom<u32> for tree::EntryMode {
type Error = u32;
fn try_from(mode: u32) -> Result<Self, Self::Error> {
Ok(match mode {
- 0o40000 => tree::EntryMode::Tree,
- 0o100644 => tree::EntryMode::Blob,
- 0o100755 => tree::EntryMode::BlobExecutable,
- 0o120000 => tree::EntryMode::Link,
- 0o160000 => tree::EntryMode::Commit,
- 0o100664 => tree::EntryMode::Blob, // rare and found in the linux kernel
- 0o100640 => tree::EntryMode::Blob, // rare and found in the Rust repo
+ 0o40000 | 0o120000 | 0o160000 => tree::EntryMode(mode as u16),
+ blob_mode if blob_mode & 0o100000 == 0o100000 => tree::EntryMode(mode as u16),
_ => return Err(mode),
})
}
@@ -116,29 +124,16 @@ mod decode {
use std::convert::TryFrom;
use bstr::ByteSlice;
- use winnow::{
- combinator::{eof, repeat, terminated},
- error::ParserError,
- prelude::*,
- stream::AsChar,
- token::{take, take_while},
- };
+ use winnow::{error::ParserError, prelude::*};
- use crate::{parse::SPACE, tree, tree::EntryRef, TreeRef};
-
- const NULL: &[u8] = b"\0";
+ use crate::{
+ tree,
+ tree::{ref_iter::mode_from_decimal, EntryRef},
+ TreeRef,
+ };
pub fn fast_entry(i: &[u8]) -> Option<(&[u8], EntryRef<'_>)> {
- let mut mode = 0u32;
- let mut spacer_pos = 1;
- for b in i.iter().take_while(|b| **b != b' ') {
- if *b < b'0' || *b > b'7' {
- return None;
- }
- mode = (mode << 3) + (b - b'0') as u32;
- spacer_pos += 1;
- }
- let (_, i) = i.split_at(spacer_pos);
+ let (mode, i) = mode_from_decimal(i)?;
let mode = tree::EntryMode::try_from(mode).ok()?;
let (filename, i) = i.split_at(i.find_byte(0)?);
let i = &i[1..];
@@ -157,24 +152,20 @@ mod decode {
))
}
- pub fn entry<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<EntryRef<'a>, E> {
- (
- terminated(take_while(5..=6, AsChar::is_dec_digit), SPACE)
- .verify_map(|mode| tree::EntryMode::try_from(mode).ok()),
- terminated(take_while(1.., |b| b != NULL[0]), NULL),
- take(20u8), // TODO(SHA256): make this compatible with other hash lengths
- )
- .map(|(mode, filename, oid): (_, &[u8], _)| EntryRef {
- mode,
- filename: filename.as_bstr(),
- oid: gix_hash::oid::try_from_bytes(oid).expect("we counted exactly 20 bytes"),
- })
- .parse_next(i)
- }
-
pub fn tree<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<TreeRef<'a>, E> {
- terminated(repeat(0.., entry), eof)
- .map(|entries| TreeRef { entries })
- .parse_next(i)
+ let mut out = Vec::new();
+ let mut i = &**i;
+ while !i.is_empty() {
+ let Some((rest, entry)) = fast_entry(i) else {
+ #[allow(clippy::unit_arg)]
+ return Err(winnow::error::ErrMode::from_error_kind(
+ &i,
+ winnow::error::ErrorKind::Verify,
+ ));
+ };
+ i = rest;
+ out.push(entry);
+ }
+ Ok(TreeRef { entries: out })
}
}