From 9918693037dce8aa4bb6f08741b6812923486c18 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:26:03 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/gix-object/src/tree/ref_iter.rs | 115 +++++++++++++++------------------ 1 file changed, 53 insertions(+), 62 deletions(-) (limited to 'vendor/gix-object/src/tree/ref_iter.rs') 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, 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 { - 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 for tree::EntryMode { type Error = u32; fn try_from(mode: u32) -> Result { 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, 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, 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 }) } } -- cgit v1.2.3