diff options
Diffstat (limited to 'vendor/gix-object/src/tree')
-rw-r--r-- | vendor/gix-object/src/tree/mod.rs | 2 | ||||
-rw-r--r-- | vendor/gix-object/src/tree/ref_iter.rs | 82 | ||||
-rw-r--r-- | vendor/gix-object/src/tree/write.rs | 4 |
3 files changed, 53 insertions, 35 deletions
diff --git a/vendor/gix-object/src/tree/mod.rs b/vendor/gix-object/src/tree/mod.rs index 147213d70..89e4def48 100644 --- a/vendor/gix-object/src/tree/mod.rs +++ b/vendor/gix-object/src/tree/mod.rs @@ -63,7 +63,7 @@ impl EntryMode { } /// An element of a [`TreeRef`][crate::TreeRef::entries]. -#[derive(PartialEq, Eq, Debug, Hash, Clone)] +#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct EntryRef<'a> { /// The kind of object to which `oid` is pointing. diff --git a/vendor/gix-object/src/tree/ref_iter.rs b/vendor/gix-object/src/tree/ref_iter.rs index fb3ba2dfc..be1244910 100644 --- a/vendor/gix-object/src/tree/ref_iter.rs +++ b/vendor/gix-object/src/tree/ref_iter.rs @@ -1,6 +1,7 @@ use std::convert::TryFrom; -use nom::error::ParseError; +use bstr::BStr; +use winnow::error::ParserError; use crate::{tree, tree::EntryRef, TreeRef, TreeRefIter}; @@ -13,8 +14,29 @@ impl<'a> TreeRefIter<'a> { impl<'a> TreeRef<'a> { /// Deserialize a Tree from `data`. - pub fn from_bytes(data: &'a [u8]) -> Result<TreeRef<'a>, crate::decode::Error> { - decode::tree(data).map(|(_, t)| t).map_err(crate::decode::Error::from) + 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) + } + + /// Find an entry named `name` knowing if the entry is a directory or not, using a binary search. + /// + /// Note that it's impossible to binary search by name alone as the sort order is special. + pub fn bisect_entry(&self, name: &BStr, is_dir: bool) -> Option<EntryRef<'a>> { + static NULL_HASH: gix_hash::ObjectId = gix_hash::Kind::shortest().null(); + + let search = EntryRef { + mode: if is_dir { + tree::EntryMode::Tree + } else { + tree::EntryMode::Blob + }, + filename: name, + oid: &NULL_HASH, + }; + self.entries + .binary_search_by(|e| e.cmp(&search)) + .ok() + .map(|idx| self.entries[idx]) } /// Create an instance of the empty tree. @@ -46,12 +68,11 @@ impl<'a> Iterator for TreeRefIter<'a> { } None => { self.data = &[]; + let empty = &[] as &[u8]; #[allow(clippy::unit_arg)] - Some(Err(nom::Err::Error(crate::decode::ParseError::from_error_kind( - &[] as &[u8], - nom::error::ErrorKind::MapRes, - )) - .into())) + Some(Err(crate::decode::Error::with_err( + winnow::error::ErrMode::from_error_kind(&empty, winnow::error::ErrorKind::Verify), + ))) } } } @@ -95,14 +116,12 @@ mod decode { use std::convert::TryFrom; use bstr::ByteSlice; - use nom::{ - bytes::complete::{tag, take, take_while1, take_while_m_n}, - character::is_digit, - combinator::all_consuming, - error::ParseError, - multi::many0, - sequence::terminated, - IResult, + use winnow::{ + combinator::{eof, repeat, terminated}, + error::ParserError, + prelude::*, + stream::AsChar, + token::{take, take_while}, }; use crate::{parse::SPACE, tree, tree::EntryRef, TreeRef}; @@ -123,7 +142,7 @@ mod decode { let mode = tree::EntryMode::try_from(mode).ok()?; let (filename, i) = i.split_at(i.find_byte(0)?); let i = &i[1..]; - const HASH_LEN_FIXME: usize = 20; // TODO: know actual /desired length or we may overshoot + const HASH_LEN_FIXME: usize = 20; // TODO(SHA256): know actual/desired length or we may overshoot let (oid, i) = match i.len() { len if len < HASH_LEN_FIXME => return None, _ => i.split_at(20), @@ -138,25 +157,24 @@ mod decode { )) } - pub fn entry<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&[u8], EntryRef<'_>, E> { - let (i, mode) = terminated(take_while_m_n(5, 6, is_digit), tag(SPACE))(i)?; - let mode = tree::EntryMode::try_from(mode) - .map_err(|invalid| nom::Err::Error(E::from_error_kind(invalid, nom::error::ErrorKind::MapRes)))?; - let (i, filename) = terminated(take_while1(|b| b != NULL[0]), tag(NULL))(i)?; - let (i, oid) = take(20u8)(i)?; // TODO: make this compatible with other hash lengths - - Ok(( - i, - EntryRef { + 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: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], TreeRef<'a>, E> { - let (i, entries) = all_consuming(many0(entry))(i)?; - Ok((i, TreeRef { entries })) + 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) } } diff --git a/vendor/gix-object/src/tree/write.rs b/vendor/gix-object/src/tree/write.rs index f826e6749..91e1dc2e0 100644 --- a/vendor/gix-object/src/tree/write.rs +++ b/vendor/gix-object/src/tree/write.rs @@ -25,7 +25,7 @@ impl From<Error> for io::Error { /// Serialization impl crate::WriteTo for Tree { /// Serialize this tree to `out` in the git internal format. - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { debug_assert_eq!( &{ let mut entries_sorted = self.entries.clone(); @@ -68,7 +68,7 @@ impl crate::WriteTo for Tree { /// Serialization impl<'a> crate::WriteTo for TreeRef<'a> { /// Serialize this tree to `out` in the git internal format. - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { debug_assert_eq!( &{ let mut entries_sorted = self.entries.clone(); |