summaryrefslogtreecommitdiffstats
path: root/vendor/gix-object/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-object/src')
-rw-r--r--vendor/gix-object/src/blob.rs20
-rw-r--r--vendor/gix-object/src/commit/decode.rs116
-rw-r--r--vendor/gix-object/src/commit/message/body.rs43
-rw-r--r--vendor/gix-object/src/commit/message/decode.rs70
-rw-r--r--vendor/gix-object/src/commit/mod.rs45
-rw-r--r--vendor/gix-object/src/commit/ref_iter.rs155
-rw-r--r--vendor/gix-object/src/commit/write.rs4
-rw-r--r--vendor/gix-object/src/data.rs6
-rw-r--r--vendor/gix-object/src/encode.rs18
-rw-r--r--vendor/gix-object/src/kind.rs24
-rw-r--r--vendor/gix-object/src/lib.rs52
-rw-r--r--vendor/gix-object/src/object/mod.rs20
-rw-r--r--vendor/gix-object/src/parse.rs106
-rw-r--r--vendor/gix-object/src/tag/decode.rs137
-rw-r--r--vendor/gix-object/src/tag/mod.rs6
-rw-r--r--vendor/gix-object/src/tag/ref_iter.rs55
-rw-r--r--vendor/gix-object/src/tag/write.rs12
-rw-r--r--vendor/gix-object/src/traits.rs12
-rw-r--r--vendor/gix-object/src/tree/mod.rs2
-rw-r--r--vendor/gix-object/src/tree/ref_iter.rs82
-rw-r--r--vendor/gix-object/src/tree/write.rs4
21 files changed, 560 insertions, 429 deletions
diff --git a/vendor/gix-object/src/blob.rs b/vendor/gix-object/src/blob.rs
index ff2eeafc8..d0a42092c 100644
--- a/vendor/gix-object/src/blob.rs
+++ b/vendor/gix-object/src/blob.rs
@@ -4,32 +4,32 @@ use crate::{Blob, BlobRef, Kind};
impl<'a> crate::WriteTo for BlobRef<'a> {
/// Write the blobs data to `out` verbatim.
- fn write_to(&self, mut out: impl io::Write) -> io::Result<()> {
+ fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
out.write_all(self.data)
}
- fn size(&self) -> usize {
- self.data.len()
- }
-
fn kind(&self) -> Kind {
Kind::Blob
}
+
+ fn size(&self) -> usize {
+ self.data.len()
+ }
}
impl crate::WriteTo for Blob {
/// Write the blobs data to `out` verbatim.
- fn write_to(&self, out: impl io::Write) -> io::Result<()> {
+ fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
self.to_ref().write_to(out)
}
- fn size(&self) -> usize {
- self.to_ref().size()
- }
-
fn kind(&self) -> Kind {
Kind::Blob
}
+
+ fn size(&self) -> usize {
+ self.to_ref().size()
+ }
}
impl Blob {
diff --git a/vendor/gix-object/src/commit/decode.rs b/vendor/gix-object/src/commit/decode.rs
index 821feaabb..0b8243ef3 100644
--- a/vendor/gix-object/src/commit/decode.rs
+++ b/vendor/gix-object/src/commit/decode.rs
@@ -1,71 +1,71 @@
use std::borrow::Cow;
-use nom::{
- branch::alt,
- bytes::complete::{is_not, tag},
- combinator::{all_consuming, opt},
- error::{context, ContextError, ParseError},
- multi::many0,
- IResult, Parser,
-};
use smallvec::SmallVec;
+use winnow::{
+ combinator::{alt, eof, opt, preceded, repeat, rest, terminated},
+ error::{AddContext, ParserError, StrContext},
+ prelude::*,
+ token::take_till1,
+};
use crate::{parse, parse::NL, BStr, ByteSlice, CommitRef};
-pub fn message<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], &'a BStr, E> {
+pub fn message<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
+ i: &mut &'a [u8],
+) -> PResult<&'a BStr, E> {
if i.is_empty() {
// newline + [message]
- return Err(nom::Err::Error(E::add_context(
- i,
- "newline + <message>",
- E::from_error_kind(i, nom::error::ErrorKind::Eof),
- )));
+ return Err(
+ winnow::error::ErrMode::from_error_kind(i, winnow::error::ErrorKind::Eof)
+ .add_context(i, StrContext::Expected("newline + <message>".into())),
+ );
}
- let (i, _) = context("a newline separates headers from the message", tag(NL))(i)?;
- Ok((&[], i.as_bstr()))
+ preceded(NL, rest.map(ByteSlice::as_bstr))
+ .context(StrContext::Expected(
+ "a newline separates headers from the message".into(),
+ ))
+ .parse_next(i)
}
-pub fn commit<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
- i: &'a [u8],
-) -> IResult<&'a [u8], CommitRef<'_>, E> {
- let (i, tree) = context("tree <40 lowercase hex char>", |i| {
- parse::header_field(i, b"tree", parse::hex_hash)
- })(i)?;
- let (i, parents) = context(
- "zero or more 'parent <40 lowercase hex char>'",
- many0(|i| parse::header_field(i, b"parent", parse::hex_hash)),
- )(i)?;
- let (i, author) = context("author <signature>", |i| {
- parse::header_field(i, b"author", parse::signature)
- })(i)?;
- let (i, committer) = context("committer <signature>", |i| {
- parse::header_field(i, b"committer", parse::signature)
- })(i)?;
- let (i, encoding) = context(
- "encoding <encoding>",
- opt(|i| parse::header_field(i, b"encoding", is_not(NL))),
- )(i)?;
- let (i, extra_headers) = context(
- "<field> <single-line|multi-line>",
- many0(alt((
- parse::any_header_field_multi_line.map(|(k, o)| (k.as_bstr(), Cow::Owned(o))),
- |i| {
- parse::any_header_field(i, is_not(NL)).map(|(i, (k, o))| (i, (k.as_bstr(), Cow::Borrowed(o.as_bstr()))))
+pub fn commit<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
+ i: &mut &'a [u8],
+) -> PResult<CommitRef<'a>, E> {
+ (
+ (|i: &mut _| parse::header_field(i, b"tree", parse::hex_hash))
+ .context(StrContext::Expected("tree <40 lowercase hex char>".into())),
+ repeat(0.., |i: &mut _| parse::header_field(i, b"parent", parse::hex_hash))
+ .map(|p: Vec<_>| p)
+ .context(StrContext::Expected(
+ "zero or more 'parent <40 lowercase hex char>'".into(),
+ )),
+ (|i: &mut _| parse::header_field(i, b"author", parse::signature))
+ .context(StrContext::Expected("author <signature>".into())),
+ (|i: &mut _| parse::header_field(i, b"committer", parse::signature))
+ .context(StrContext::Expected("committer <signature>".into())),
+ opt(|i: &mut _| parse::header_field(i, b"encoding", take_till1(NL)))
+ .context(StrContext::Expected("encoding <encoding>".into())),
+ repeat(
+ 0..,
+ alt((
+ parse::any_header_field_multi_line.map(|(k, o)| (k.as_bstr(), Cow::Owned(o))),
+ |i: &mut _| {
+ parse::any_header_field(i, take_till1(NL)).map(|(k, o)| (k.as_bstr(), Cow::Borrowed(o.as_bstr())))
+ },
+ )),
+ )
+ .context(StrContext::Expected("<field> <single-line|multi-line>".into())),
+ terminated(message, eof),
+ )
+ .map(
+ |(tree, parents, author, committer, encoding, extra_headers, message)| CommitRef {
+ tree,
+ parents: SmallVec::from(parents),
+ author,
+ committer,
+ encoding: encoding.map(ByteSlice::as_bstr),
+ message,
+ extra_headers,
},
- ))),
- )(i)?;
- let (i, message) = all_consuming(message)(i)?;
-
- Ok((
- i,
- CommitRef {
- tree,
- parents: SmallVec::from(parents),
- author,
- committer,
- encoding: encoding.map(ByteSlice::as_bstr),
- message,
- extra_headers,
- },
- ))
+ )
+ .parse_next(i)
}
diff --git a/vendor/gix-object/src/commit/message/body.rs b/vendor/gix-object/src/commit/message/body.rs
index 855f031be..6301bf30e 100644
--- a/vendor/gix-object/src/commit/message/body.rs
+++ b/vendor/gix-object/src/commit/message/body.rs
@@ -1,11 +1,10 @@
use std::ops::Deref;
-use nom::{
- bytes::complete::{tag, take_until1},
- combinator::all_consuming,
- error::{ErrorKind, ParseError},
- sequence::terminated,
- IResult,
+use winnow::{
+ combinator::{eof, rest, separated_pair, terminated},
+ error::{ErrorKind, ParserError},
+ prelude::*,
+ token::take_until1,
};
use crate::{
@@ -32,12 +31,14 @@ pub struct TrailerRef<'a> {
pub value: &'a BStr,
}
-fn parse_single_line_trailer<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a BStr, &'a BStr), E> {
- let (value, token) = terminated(take_until1(b":".as_ref()), tag(b": "))(i.trim_end())?;
+fn parse_single_line_trailer<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<(&'a BStr, &'a BStr), E> {
+ *i = i.trim_end();
+ let (token, value) = separated_pair(take_until1(b":".as_ref()), b": ", rest).parse_next(i)?;
+
if token.trim_end().len() != token.len() || value.trim_start().len() != value.len() {
- Err(nom::Err::Failure(E::from_error_kind(i, ErrorKind::Fail)))
+ Err(winnow::error::ErrMode::from_error_kind(i, ErrorKind::Fail).cut())
} else {
- Ok((&[], (token.as_bstr(), value.as_bstr())))
+ Ok((token.as_bstr(), value.as_bstr()))
}
}
@@ -48,15 +49,15 @@ impl<'a> Iterator for Trailers<'a> {
if self.cursor.is_empty() {
return None;
}
- for line in self.cursor.lines_with_terminator() {
+ for mut line in self.cursor.lines_with_terminator() {
self.cursor = &self.cursor[line.len()..];
- if let Some(trailer) =
- all_consuming(parse_single_line_trailer::<()>)(line)
- .ok()
- .map(|(_, (token, value))| TrailerRef {
- token: token.trim().as_bstr(),
- value: value.trim().as_bstr(),
- })
+ if let Some(trailer) = terminated(parse_single_line_trailer::<()>, eof)
+ .parse_next(&mut line)
+ .ok()
+ .map(|(token, value)| TrailerRef {
+ token: token.trim().as_bstr(),
+ value: value.trim().as_bstr(),
+ })
{
return Some(trailer);
}
@@ -118,7 +119,7 @@ mod test_parse_trailer {
use super::*;
fn parse(input: &str) -> (&BStr, &BStr) {
- parse_single_line_trailer::<()>(input.as_bytes()).unwrap().1
+ parse_single_line_trailer::<()>.parse_peek(input.as_bytes()).unwrap().1
}
#[test]
@@ -141,8 +142,8 @@ mod test_parse_trailer {
#[test]
fn extra_whitespace_before_token_or_value_is_error() {
- assert!(parse_single_line_trailer::<()>(b"foo : bar").is_err());
- assert!(parse_single_line_trailer::<()>(b"foo: bar").is_err())
+ assert!(parse_single_line_trailer::<()>.parse_peek(b"foo : bar").is_err());
+ assert!(parse_single_line_trailer::<()>.parse_peek(b"foo: bar").is_err())
}
#[test]
diff --git a/vendor/gix-object/src/commit/message/decode.rs b/vendor/gix-object/src/commit/message/decode.rs
index 6224909bd..8038009b4 100644
--- a/vendor/gix-object/src/commit/message/decode.rs
+++ b/vendor/gix-object/src/commit/message/decode.rs
@@ -1,57 +1,49 @@
-use nom::{
- branch::alt,
- bytes::complete::{tag, take_till1},
- combinator::all_consuming,
- error::ParseError,
- sequence::pair,
- IResult,
+use winnow::{
+ combinator::{alt, eof, preceded, rest, terminated},
+ error::ParserError,
+ prelude::*,
+ stream::{Offset, Stream},
+ token::take_till1,
};
use crate::bstr::{BStr, ByteSlice};
-pub(crate) fn newline<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8], E> {
- alt((tag(b"\r\n"), tag(b"\n")))(i)
+pub(crate) fn newline<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<&'a [u8], E> {
+ alt((b"\n", b"\r\n")).parse_next(i)
}
-fn subject_and_body<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a BStr, Option<&'a BStr>), E> {
- let mut c = i;
- let mut consumed_bytes = 0;
- while !c.is_empty() {
- c = match take_till1::<_, _, E>(|c| c == b'\n' || c == b'\r')(c) {
- Ok((i1, segment)) => {
- consumed_bytes += segment.len();
- match pair::<_, _, _, E, _, _>(newline, newline)(i1) {
- Ok((body, _)) => {
- return Ok((
- &[],
- (
- i[0usize..consumed_bytes].as_bstr(),
- (!body.is_empty()).then(|| body.as_bstr()),
- ),
- ));
+fn subject_and_body<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<(&'a BStr, Option<&'a BStr>), E> {
+ let start_i = *i;
+ let start = i.checkpoint();
+ while !i.is_empty() {
+ match take_till1::<_, _, E>(|c| c == b'\n' || c == b'\r').parse_next(i) {
+ Ok(_) => {
+ let consumed_bytes = i.offset_from(&start);
+ match preceded((newline::<E>, newline::<E>), rest).parse_next(i) {
+ Ok(body) => {
+ let body = (!body.is_empty()).then(|| body.as_bstr());
+ return Ok((start_i[0usize..consumed_bytes].as_bstr(), body));
}
- Err(_) => match i1.get(1..) {
- Some(next) => {
- consumed_bytes += 1;
- next
- }
+ Err(_) => match i.next_token() {
+ Some(_) => {}
None => break,
},
}
}
- Err(_) => match c.get(1..) {
- Some(next) => {
- consumed_bytes += 1;
- next
- }
+ Err(_) => match i.next_token() {
+ Some(_) => {}
None => break,
},
- };
+ }
}
- Ok((&[], (i.as_bstr(), None)))
+
+ i.reset(start);
+ rest.map(|r: &[u8]| (r.as_bstr(), None)).parse_next(i)
}
/// Returns title and body, without separator
-pub fn message(input: &[u8]) -> (&BStr, Option<&BStr>) {
- all_consuming(subject_and_body::<()>)(input).expect("cannot fail").1
+pub fn message(mut input: &[u8]) -> (&BStr, Option<&BStr>) {
+ terminated(subject_and_body::<()>, eof)
+ .parse_next(&mut input)
+ .expect("cannot fail")
}
diff --git a/vendor/gix-object/src/commit/mod.rs b/vendor/gix-object/src/commit/mod.rs
index 9e135df28..b3de9b0a4 100644
--- a/vendor/gix-object/src/commit/mod.rs
+++ b/vendor/gix-object/src/commit/mod.rs
@@ -1,4 +1,6 @@
-use bstr::{BStr, ByteSlice};
+use std::ops::Range;
+
+use bstr::{BStr, BString, ByteSlice};
use crate::{Commit, CommitRef, TagRef};
@@ -21,16 +23,49 @@ pub struct MessageRef<'a> {
pub body: Option<&'a BStr>,
}
+/// The raw commit data, parseable by [`CommitRef`] or [`Commit`], which was fed into a program to produce a signature.
+///
+/// See [`extract_signature()`](crate::CommitRefIter::signature()) for how to obtain it.
+// TODO: implement `std::io::Read` to avoid allocations
+#[derive(PartialEq, Eq, Debug, Hash, Clone)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct SignedData<'a> {
+ /// The raw commit data that includes the signature.
+ data: &'a [u8],
+ /// The byte range at which we find the signature. All but the signature is the data that was signed.
+ signature_range: Range<usize>,
+}
+
+impl SignedData<'_> {
+ /// Convenience method to obtain a copy of the signed data.
+ pub fn to_bstring(&self) -> BString {
+ let mut buf = BString::from(&self.data[..self.signature_range.start]);
+ buf.extend_from_slice(&self.data[self.signature_range.end..]);
+ buf
+ }
+}
+
+impl From<SignedData<'_>> for BString {
+ fn from(value: SignedData<'_>) -> Self {
+ value.to_bstring()
+ }
+}
+
///
pub mod ref_iter;
mod write;
+/// Lifecycle
impl<'a> CommitRef<'a> {
/// Deserialize a commit from the given `data` bytes while avoiding most allocations.
- pub fn from_bytes(data: &'a [u8]) -> Result<CommitRef<'a>, crate::decode::Error> {
- decode::commit(data).map(|(_, t)| t).map_err(crate::decode::Error::from)
+ pub fn from_bytes(mut data: &'a [u8]) -> Result<CommitRef<'a>, crate::decode::Error> {
+ decode::commit(&mut data).map_err(crate::decode::Error::with_err)
}
+}
+
+/// Access
+impl<'a> CommitRef<'a> {
/// Return the `tree` fields hash digest.
pub fn tree(&self) -> gix_hash::ObjectId {
gix_hash::ObjectId::from_hex(self.tree).expect("prior validation of tree hash during parsing")
@@ -45,7 +80,7 @@ impl<'a> CommitRef<'a> {
/// Returns a convenient iterator over all extra headers.
pub fn extra_headers(&self) -> crate::commit::ExtraHeaders<impl Iterator<Item = (&BStr, &BStr)>> {
- crate::commit::ExtraHeaders::new(self.extra_headers.iter().map(|(k, v)| (*k, v.as_ref())))
+ ExtraHeaders::new(self.extra_headers.iter().map(|(k, v)| (*k, v.as_ref())))
}
/// Return the author, with whitespace trimmed.
@@ -68,7 +103,7 @@ impl<'a> CommitRef<'a> {
}
/// Returns the time at which this commit was created.
- pub fn time(&self) -> gix_actor::Time {
+ pub fn time(&self) -> gix_date::Time {
self.committer.time
}
}
diff --git a/vendor/gix-object/src/commit/ref_iter.rs b/vendor/gix-object/src/commit/ref_iter.rs
index 454f69ac0..4401384ca 100644
--- a/vendor/gix-object/src/commit/ref_iter.rs
+++ b/vendor/gix-object/src/commit/ref_iter.rs
@@ -1,15 +1,21 @@
-use std::borrow::Cow;
+use std::{borrow::Cow, ops::Range};
use bstr::BStr;
use gix_hash::{oid, ObjectId};
-use nom::{
- branch::alt,
- bytes::complete::is_not,
- combinator::{all_consuming, opt},
- error::context,
+use winnow::{
+ combinator::{alt, eof, opt, terminated},
+ error::StrContext,
+ prelude::*,
+ token::take_till1,
};
-use crate::{bstr::ByteSlice, commit::decode, parse, parse::NL, CommitRefIter};
+use crate::{
+ bstr::ByteSlice,
+ commit::{decode, SignedData},
+ parse,
+ parse::NL,
+ CommitRefIter,
+};
#[derive(Copy, Clone)]
pub(crate) enum SignatureKind {
@@ -30,6 +36,7 @@ pub(crate) enum State {
Message,
}
+/// Lifecycle
impl<'a> CommitRefIter<'a> {
/// Create a commit iterator from data.
pub fn from_bytes(data: &'a [u8]) -> CommitRefIter<'a> {
@@ -38,6 +45,37 @@ impl<'a> CommitRefIter<'a> {
state: State::default(),
}
}
+}
+
+/// Access
+impl<'a> CommitRefIter<'a> {
+ /// Parse `data` as commit and return its PGP signature, along with *all non-signature* data as [`SignedData`], or `None`
+ /// if the commit isn't signed.
+ ///
+ /// This allows the caller to validate the signature by passing the signed data along with the signature back to the program
+ /// that created it.
+ pub fn signature(data: &'a [u8]) -> Result<Option<(Cow<'a, BStr>, SignedData<'a>)>, crate::decode::Error> {
+ let mut signature_and_range = None;
+
+ let raw_tokens = CommitRefIterRaw {
+ data,
+ state: State::default(),
+ offset: 0,
+ };
+ for token in raw_tokens {
+ let token = token?;
+ if let Token::ExtraHeader((name, value)) = &token.token {
+ if *name == "gpgsig" {
+ // keep track of the signature range alongside the signature data,
+ // because all but the signature is the signed data.
+ signature_and_range = Some((value.clone(), token.token_range));
+ break;
+ }
+ }
+ }
+
+ Ok(signature_and_range.map(|(sig, signature_range)| (sig, SignedData { data, signature_range })))
+ }
/// Returns the object id of this commits tree if it is the first function called and if there is no error in decoding
/// the data.
@@ -106,7 +144,7 @@ impl<'a> CommitRefIter<'a> {
_ => None,
})
.transpose()
- .map(|msg| msg.unwrap_or_default())
+ .map(Option::unwrap_or_default)
}
}
@@ -115,13 +153,21 @@ fn missing_field() -> crate::decode::Error {
}
impl<'a> CommitRefIter<'a> {
+ #[inline]
fn next_inner(i: &'a [u8], state: &mut State) -> Result<(&'a [u8], Token<'a>), crate::decode::Error> {
+ Self::next_inner_(i, state).map_err(crate::decode::Error::with_err)
+ }
+
+ fn next_inner_(
+ mut i: &'a [u8],
+ state: &mut State,
+ ) -> Result<(&'a [u8], Token<'a>), winnow::error::ErrMode<crate::decode::ParseError>> {
use State::*;
Ok(match state {
Tree => {
- let (i, tree) = context("tree <40 lowercase hex char>", |i| {
- parse::header_field(i, b"tree", parse::hex_hash)
- })(i)?;
+ let tree = (|i: &mut _| parse::header_field(i, b"tree", parse::hex_hash))
+ .context(StrContext::Expected("tree <40 lowercase hex char>".into()))
+ .parse_next(&mut i)?;
*state = State::Parents;
(
i,
@@ -131,10 +177,9 @@ impl<'a> CommitRefIter<'a> {
)
}
Parents => {
- let (i, parent) = context(
- "commit <40 lowercase hex char>",
- opt(|i| parse::header_field(i, b"parent", parse::hex_hash)),
- )(i)?;
+ let parent = opt(|i: &mut _| parse::header_field(i, b"parent", parse::hex_hash))
+ .context(StrContext::Expected("commit <40 lowercase hex char>".into()))
+ .parse_next(&mut i)?;
match parent {
Some(parent) => (
i,
@@ -146,7 +191,7 @@ impl<'a> CommitRefIter<'a> {
*state = State::Signature {
of: SignatureKind::Author,
};
- return Self::next_inner(i, state);
+ return Self::next_inner_(i, state);
}
}
}
@@ -162,7 +207,9 @@ impl<'a> CommitRefIter<'a> {
(&b"committer"[..], "committer <signature>")
}
};
- let (i, signature) = context(err_msg, |i| parse::header_field(i, field_name, parse::signature))(i)?;
+ let signature = (|i: &mut _| parse::header_field(i, field_name, parse::signature))
+ .context(StrContext::Expected(err_msg.into()))
+ .parse_next(&mut i)?;
(
i,
match who {
@@ -172,37 +219,35 @@ impl<'a> CommitRefIter<'a> {
)
}
Encoding => {
- let (i, encoding) = context(
- "encoding <encoding>",
- opt(|i| parse::header_field(i, b"encoding", is_not(NL))),
- )(i)?;
+ let encoding = opt(|i: &mut _| parse::header_field(i, b"encoding", take_till1(NL)))
+ .context(StrContext::Expected("encoding <encoding>".into()))
+ .parse_next(&mut i)?;
*state = State::ExtraHeaders;
match encoding {
Some(encoding) => (i, Token::Encoding(encoding.as_bstr())),
- None => return Self::next_inner(i, state),
+ None => return Self::next_inner_(i, state),
}
}
ExtraHeaders => {
- let (i, extra_header) = context(
- "<field> <single-line|multi-line>",
- opt(alt((
- |i| parse::any_header_field_multi_line(i).map(|(i, (k, o))| (i, (k.as_bstr(), Cow::Owned(o)))),
- |i| {
- parse::any_header_field(i, is_not(NL))
- .map(|(i, (k, o))| (i, (k.as_bstr(), Cow::Borrowed(o.as_bstr()))))
- },
- ))),
- )(i)?;
+ let extra_header = opt(alt((
+ |i: &mut _| parse::any_header_field_multi_line(i).map(|(k, o)| (k.as_bstr(), Cow::Owned(o))),
+ |i: &mut _| {
+ parse::any_header_field(i, take_till1(NL))
+ .map(|(k, o)| (k.as_bstr(), Cow::Borrowed(o.as_bstr())))
+ },
+ )))
+ .context(StrContext::Expected("<field> <single-line|multi-line>".into()))
+ .parse_next(&mut i)?;
match extra_header {
Some(extra_header) => (i, Token::ExtraHeader(extra_header)),
None => {
*state = State::Message;
- return Self::next_inner(i, state);
+ return Self::next_inner_(i, state);
}
}
}
Message => {
- let (i, message) = all_consuming(decode::message)(i)?;
+ let message = terminated(decode::message, eof).parse_next(&mut i)?;
debug_assert!(
i.is_empty(),
"we should have consumed all data - otherwise iter may go forever"
@@ -233,6 +278,48 @@ impl<'a> Iterator for CommitRefIter<'a> {
}
}
+/// A variation of [`CommitRefIter`] that return's [`RawToken`]s instead.
+struct CommitRefIterRaw<'a> {
+ data: &'a [u8],
+ state: State,
+ offset: usize,
+}
+
+impl<'a> Iterator for CommitRefIterRaw<'a> {
+ type Item = Result<RawToken<'a>, crate::decode::Error>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.data.is_empty() {
+ return None;
+ }
+ match CommitRefIter::next_inner(self.data, &mut self.state) {
+ Ok((remaining, token)) => {
+ let consumed = self.data.len() - remaining.len();
+ let start = self.offset;
+ let end = start + consumed;
+ self.offset = end;
+
+ self.data = remaining;
+ Some(Ok(RawToken {
+ token,
+ token_range: start..end,
+ }))
+ }
+ Err(err) => {
+ self.data = &[];
+ Some(Err(err))
+ }
+ }
+ }
+}
+
+/// A combination of a parsed [`Token`] as well as the range of bytes that were consumed to parse it.
+struct RawToken<'a> {
+ /// The parsed token.
+ token: Token<'a>,
+ token_range: Range<usize>,
+}
+
/// A token returned by the [commit iterator][CommitRefIter].
#[allow(missing_docs)]
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
diff --git a/vendor/gix-object/src/commit/write.rs b/vendor/gix-object/src/commit/write.rs
index e498789a2..667d25763 100644
--- a/vendor/gix-object/src/commit/write.rs
+++ b/vendor/gix-object/src/commit/write.rs
@@ -6,7 +6,7 @@ use crate::{encode, encode::NL, Commit, CommitRef, Kind};
impl crate::WriteTo for Commit {
/// Serializes this instance to `out` in the git serialization format.
- fn write_to(&self, mut out: impl io::Write) -> io::Result<()> {
+ fn write_to(&self, mut out: &mut dyn io::Write) -> io::Result<()> {
encode::trusted_header_id(b"tree", &self.tree, &mut out)?;
for parent in &self.parents {
encode::trusted_header_id(b"parent", parent, &mut out)?;
@@ -52,7 +52,7 @@ impl crate::WriteTo for Commit {
impl<'a> crate::WriteTo for CommitRef<'a> {
/// Serializes this instance to `out` in the git serialization format.
- fn write_to(&self, mut out: impl io::Write) -> io::Result<()> {
+ fn write_to(&self, mut out: &mut dyn io::Write) -> io::Result<()> {
encode::trusted_header_id(b"tree", &self.tree(), &mut out)?;
for parent in self.parents() {
encode::trusted_header_id(b"parent", &parent, &mut out)?;
diff --git a/vendor/gix-object/src/data.rs b/vendor/gix-object/src/data.rs
index e66360357..cea807684 100644
--- a/vendor/gix-object/src/data.rs
+++ b/vendor/gix-object/src/data.rs
@@ -67,8 +67,7 @@ pub mod verify {
/// Compute the checksum of `self` and compare it with the `desired` hash.
/// If the hashes do not match, an [`Error`] is returned, containing the actual
/// hash of `self`.
- pub fn verify_checksum(&self, desired: impl AsRef<gix_hash::oid>) -> Result<(), Error> {
- let desired = desired.as_ref();
+ pub fn verify_checksum(&self, desired: &gix_hash::oid) -> Result<(), Error> {
let actual_id = crate::compute_hash(desired.kind(), self.kind, self.data);
if desired != actual_id {
return Err(Error::ChecksumMismatch {
@@ -87,6 +86,9 @@ mod tests {
#[test]
fn size_of_object() {
+ #[cfg(target_pointer_width = "64")]
assert_eq!(std::mem::size_of::<Data<'_>>(), 24, "this shouldn't change unnoticed");
+ #[cfg(target_pointer_width = "32")]
+ assert_eq!(std::mem::size_of::<Data<'_>>(), 12, "this shouldn't change unnoticed");
}
}
diff --git a/vendor/gix-object/src/encode.rs b/vendor/gix-object/src/encode.rs
index 6d291c92a..3ba7db0b5 100644
--- a/vendor/gix-object/src/encode.rs
+++ b/vendor/gix-object/src/encode.rs
@@ -34,9 +34,9 @@ impl From<Error> for io::Error {
}
}
-pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], mut out: impl io::Write) -> io::Result<()> {
+pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
let mut lines = value.as_bstr().split_str(b"\n");
- trusted_header_field(name, lines.next().ok_or(Error::EmptyValue)?, &mut out)?;
+ trusted_header_field(name, lines.next().ok_or(Error::EmptyValue)?, out)?;
for line in lines {
out.write_all(SPACE)?;
out.write_all(line)?;
@@ -45,7 +45,7 @@ pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], mut out: impl i
Ok(())
}
-pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], mut out: impl io::Write) -> io::Result<()> {
+pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
out.write_all(name)?;
out.write_all(SPACE)?;
out.write_all(value)?;
@@ -55,22 +55,26 @@ pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], mut out: impl io::
pub(crate) fn trusted_header_signature(
name: &[u8],
value: &gix_actor::SignatureRef<'_>,
- mut out: impl io::Write,
+ out: &mut dyn io::Write,
) -> io::Result<()> {
out.write_all(name)?;
out.write_all(SPACE)?;
- value.write_to(&mut out)?;
+ value.write_to(out)?;
out.write_all(NL)
}
-pub(crate) fn trusted_header_id(name: &[u8], value: &gix_hash::ObjectId, mut out: impl io::Write) -> io::Result<()> {
+pub(crate) fn trusted_header_id(
+ name: &[u8],
+ value: &gix_hash::ObjectId,
+ mut out: &mut dyn io::Write,
+) -> io::Result<()> {
out.write_all(name)?;
out.write_all(SPACE)?;
value.write_hex_to(&mut out)?;
out.write_all(NL)
}
-pub(crate) fn header_field(name: &[u8], value: &[u8], out: impl io::Write) -> io::Result<()> {
+pub(crate) fn header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
if value.is_empty() {
return Err(Error::EmptyValue.into());
}
diff --git a/vendor/gix-object/src/kind.rs b/vendor/gix-object/src/kind.rs
index 86df251bf..93e457ca4 100644
--- a/vendor/gix-object/src/kind.rs
+++ b/vendor/gix-object/src/kind.rs
@@ -10,6 +10,7 @@ pub enum Error {
InvalidObjectKind { kind: bstr::BString },
}
+/// Initialization
impl Kind {
/// Parse a `Kind` from its serialized loose git objects.
pub fn from_bytes(s: &[u8]) -> Result<Kind, Error> {
@@ -21,7 +22,10 @@ impl Kind {
_ => return Err(Error::InvalidObjectKind { kind: s.into() }),
})
}
+}
+/// Access
+impl Kind {
/// Return the name of `self` for use in serialized loose git objects.
pub fn as_bytes(&self) -> &[u8] {
match self {
@@ -31,6 +35,26 @@ impl Kind {
Kind::Tag => b"tag",
}
}
+
+ /// Returns `true` if this instance is representing a commit.
+ pub fn is_commit(&self) -> bool {
+ matches!(self, Kind::Commit)
+ }
+
+ /// Returns `true` if this instance is representing a tree.
+ pub fn is_tree(&self) -> bool {
+ matches!(self, Kind::Tree)
+ }
+
+ /// Returns `true` if this instance is representing a tag.
+ pub fn is_tag(&self) -> bool {
+ matches!(self, Kind::Tag)
+ }
+
+ /// Returns `true` if this instance is representing a blob.
+ pub fn is_blob(&self) -> bool {
+ matches!(self, Kind::Blob)
+ }
}
impl fmt::Display for Kind {
diff --git a/vendor/gix-object/src/lib.rs b/vendor/gix-object/src/lib.rs
index d6c9fb760..56e0019fd 100644
--- a/vendor/gix-object/src/lib.rs
+++ b/vendor/gix-object/src/lib.rs
@@ -14,6 +14,8 @@ use std::borrow::Cow;
/// For convenience to allow using `bstr` without adding it to own cargo manifest.
pub use bstr;
use bstr::{BStr, BString, ByteSlice};
+/// For convenience to allow using `gix-date` without adding it to own cargo manifest.
+pub use gix_date as date;
use smallvec::SmallVec;
///
@@ -213,6 +215,8 @@ pub enum Object {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TreeRef<'a> {
/// The directories and files contained in this tree.
+ ///
+ /// Beware that the sort order isn't *quite* by name, so one may bisect only with a [`tree::EntryRef`] to handle ordering correctly.
#[cfg_attr(feature = "serde", serde(borrow))]
pub entries: Vec<tree::EntryRef<'a>>,
}
@@ -229,6 +233,8 @@ pub struct TreeRefIter<'a> {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Tree {
/// The directories and files contained in this tree. They must be and remain sorted by [`filename`][tree::Entry::filename].
+ ///
+ /// Beware that the sort order isn't *quite* by name, so one may bisect only with a [`tree::Entry`] to handle ordering correctly.
pub entries: Vec<tree::Entry>,
}
@@ -252,16 +258,12 @@ pub struct Data<'a> {
pub mod decode {
#[cfg(feature = "verbose-object-parsing-errors")]
mod _decode {
- use crate::bstr::{BString, ByteSlice};
-
/// The type to be used for parse errors.
- pub type ParseError<'a> = nom::error::VerboseError<&'a [u8]>;
- /// The owned type to be used for parse errors.
- pub type ParseErrorOwned = nom::error::VerboseError<BString>;
+ pub type ParseError = winnow::error::ContextError<winnow::error::StrContext>;
pub(crate) fn empty_error() -> Error {
Error {
- inner: nom::error::VerboseError::<BString> { errors: Vec::new() },
+ inner: winnow::error::ContextError::new(),
}
}
@@ -269,22 +271,13 @@ pub mod decode {
#[derive(Debug, Clone)]
pub struct Error {
/// The actual error
- pub inner: ParseErrorOwned,
+ pub inner: ParseError,
}
- impl<'a> From<nom::Err<ParseError<'a>>> for Error {
- fn from(v: nom::Err<ParseError<'a>>) -> Self {
- Error {
- inner: match v {
- nom::Err::Error(err) | nom::Err::Failure(err) => nom::error::VerboseError {
- errors: err
- .errors
- .into_iter()
- .map(|(i, v)| (i.as_bstr().to_owned(), v))
- .collect(),
- },
- nom::Err::Incomplete(_) => unreachable!("we don't have streaming parsers"),
- },
+ impl Error {
+ pub(crate) fn with_err(err: winnow::error::ErrMode<ParseError>) -> Self {
+ Self {
+ inner: err.into_inner().expect("we don't have streaming parsers"),
}
}
}
@@ -300,9 +293,7 @@ pub mod decode {
#[cfg(not(feature = "verbose-object-parsing-errors"))]
mod _decode {
/// The type to be used for parse errors, discards everything and is zero size
- pub type ParseError<'a> = ();
- /// The owned type to be used for parse errors, discards everything and is zero size
- pub type ParseErrorOwned = ();
+ pub type ParseError = ();
pub(crate) fn empty_error() -> Error {
Error { inner: () }
@@ -312,16 +303,13 @@ pub mod decode {
#[derive(Debug, Clone)]
pub struct Error {
/// The actual error
- pub inner: ParseErrorOwned,
+ pub inner: ParseError,
}
- impl<'a> From<nom::Err<ParseError<'a>>> for Error {
- fn from(v: nom::Err<ParseError<'a>>) -> Self {
- Error {
- inner: match v {
- nom::Err::Error(err) | nom::Err::Failure(err) => err,
- nom::Err::Incomplete(_) => unreachable!("we don't have streaming parsers"),
- },
+ impl Error {
+ pub(crate) fn with_err(err: winnow::error::ErrMode<ParseError>) -> Self {
+ Self {
+ inner: err.into_inner().expect("we don't have streaming parsers"),
}
}
}
@@ -333,7 +321,7 @@ pub mod decode {
}
}
pub(crate) use _decode::empty_error;
- pub use _decode::{Error, ParseError, ParseErrorOwned};
+ pub use _decode::{Error, ParseError};
impl std::error::Error for Error {}
/// Returned by [`loose_header()`]
diff --git a/vendor/gix-object/src/object/mod.rs b/vendor/gix-object/src/object/mod.rs
index c0f9dcd52..bebc1cc65 100644
--- a/vendor/gix-object/src/object/mod.rs
+++ b/vendor/gix-object/src/object/mod.rs
@@ -10,7 +10,7 @@ mod write {
/// Serialization
impl<'a> WriteTo for ObjectRef<'a> {
/// Write the contained object to `out` in the git serialization format.
- fn write_to(&self, out: impl io::Write) -> io::Result<()> {
+ fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
use crate::ObjectRef::*;
match self {
Tree(v) => v.write_to(out),
@@ -20,6 +20,10 @@ mod write {
}
}
+ fn kind(&self) -> Kind {
+ self.kind()
+ }
+
fn size(&self) -> usize {
use crate::ObjectRef::*;
match self {
@@ -29,16 +33,12 @@ mod write {
Tag(v) => v.size(),
}
}
-
- fn kind(&self) -> Kind {
- self.kind()
- }
}
/// Serialization
impl WriteTo for Object {
/// Write the contained object to `out` in the git serialization format.
- fn write_to(&self, out: impl io::Write) -> io::Result<()> {
+ fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
use crate::Object::*;
match self {
Tree(v) => v.write_to(out),
@@ -48,6 +48,10 @@ mod write {
}
}
+ fn kind(&self) -> Kind {
+ self.kind()
+ }
+
fn size(&self) -> usize {
use crate::Object::*;
match self {
@@ -57,10 +61,6 @@ mod write {
Tag(v) => v.size(),
}
}
-
- fn kind(&self) -> Kind {
- self.kind()
- }
}
}
diff --git a/vendor/gix-object/src/parse.rs b/vendor/gix-object/src/parse.rs
index 20dd443c0..0013d9b72 100644
--- a/vendor/gix-object/src/parse.rs
+++ b/vendor/gix-object/src/parse.rs
@@ -1,11 +1,10 @@
use bstr::{BStr, BString, ByteVec};
-use nom::{
- bytes::complete::{is_not, tag, take_until, take_while_m_n},
- combinator::{peek, recognize},
- error::{context, ContextError, ParseError},
- multi::many1_count,
- sequence::{preceded, terminated, tuple},
- IResult,
+use winnow::{
+ combinator::{preceded, repeat, terminated},
+ error::{AddContext, ParserError, StrContext},
+ prelude::*,
+ token::{take_till1, take_until0, take_while},
+ Parser,
};
use crate::ByteSlice;
@@ -14,68 +13,63 @@ pub(crate) const NL: &[u8] = b"\n";
pub(crate) const SPACE: &[u8] = b" ";
const SPACE_OR_NL: &[u8] = b" \n";
-pub(crate) fn any_header_field_multi_line<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
- i: &'a [u8],
-) -> IResult<&'a [u8], (&'a [u8], BString), E> {
- let (i, (k, o)) = context(
- "name <multi-line-value>",
- peek(tuple((
- terminated(is_not(SPACE_OR_NL), tag(SPACE)),
- recognize(tuple((
- is_not(NL),
- tag(NL),
- many1_count(terminated(tuple((tag(SPACE), take_until(NL))), tag(NL))),
- ))),
- ))),
- )(i)?;
- assert!(!o.is_empty(), "we have parsed more than one value here");
- let end = &o[o.len() - 1] as *const u8 as usize;
- let start_input = &i[0] as *const u8 as usize;
-
- let bytes = o[..o.len() - 1].as_bstr();
- let mut out = BString::from(Vec::with_capacity(bytes.len()));
- let mut lines = bytes.lines();
- out.push_str(lines.next().expect("first line"));
- for line in lines {
- out.push(b'\n');
- out.push_str(&line[1..]); // cut leading space
- }
- Ok((&i[end - start_input + 1..], (k, out)))
+pub(crate) fn any_header_field_multi_line<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
+ i: &mut &'a [u8],
+) -> PResult<(&'a [u8], BString), E> {
+ (
+ terminated(take_till1(SPACE_OR_NL), SPACE),
+ (
+ take_till1(NL),
+ NL,
+ repeat(1.., terminated((SPACE, take_until0(NL)), NL)).map(|()| ()),
+ )
+ .recognize()
+ .map(|o: &[u8]| {
+ let bytes = o.as_bstr();
+ let mut out = BString::from(Vec::with_capacity(bytes.len()));
+ let mut lines = bytes.lines();
+ out.push_str(lines.next().expect("first line"));
+ for line in lines {
+ out.push(b'\n');
+ out.push_str(&line[1..]); // cut leading space
+ }
+ out
+ }),
+ )
+ .context(StrContext::Expected("name <multi-line-value>".into()))
+ .parse_next(i)
}
-pub(crate) fn header_field<'a, T, E: ParseError<&'a [u8]>>(
- i: &'a [u8],
+pub(crate) fn header_field<'a, T, E: ParserError<&'a [u8]>>(
+ i: &mut &'a [u8],
name: &'static [u8],
- parse_value: impl Fn(&'a [u8]) -> IResult<&'a [u8], T, E>,
-) -> IResult<&'a [u8], T, E> {
- terminated(preceded(terminated(tag(name), tag(SPACE)), parse_value), tag(NL))(i)
+ parse_value: impl Parser<&'a [u8], T, E>,
+) -> PResult<T, E> {
+ terminated(preceded(terminated(name, SPACE), parse_value), NL).parse_next(i)
}
-pub(crate) fn any_header_field<'a, T, E: ParseError<&'a [u8]>>(
- i: &'a [u8],
- parse_value: impl Fn(&'a [u8]) -> IResult<&'a [u8], T, E>,
-) -> IResult<&'a [u8], (&'a [u8], T), E> {
- terminated(
- tuple((terminated(is_not(SPACE_OR_NL), tag(SPACE)), parse_value)),
- tag(NL),
- )(i)
+pub(crate) fn any_header_field<'a, T, E: ParserError<&'a [u8]>>(
+ i: &mut &'a [u8],
+ parse_value: impl Parser<&'a [u8], T, E>,
+) -> PResult<(&'a [u8], T), E> {
+ terminated((terminated(take_till1(SPACE_OR_NL), SPACE), parse_value), NL).parse_next(i)
}
fn is_hex_digit_lc(b: u8) -> bool {
matches!(b, b'0'..=b'9' | b'a'..=b'f')
}
-pub fn hex_hash<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], &'a BStr, E> {
- take_while_m_n(
- gix_hash::Kind::shortest().len_in_hex(),
- gix_hash::Kind::longest().len_in_hex(),
+pub fn hex_hash<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<&'a BStr, E> {
+ take_while(
+ gix_hash::Kind::shortest().len_in_hex()..=gix_hash::Kind::longest().len_in_hex(),
is_hex_digit_lc,
- )(i)
- .map(|(i, hex)| (i, hex.as_bstr()))
+ )
+ .map(ByteSlice::as_bstr)
+ .parse_next(i)
}
-pub(crate) fn signature<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
- i: &'a [u8],
-) -> IResult<&'a [u8], gix_actor::SignatureRef<'a>, E> {
+pub(crate) fn signature<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
+ i: &mut &'a [u8],
+) -> PResult<gix_actor::SignatureRef<'a>, E> {
gix_actor::signature::decode(i)
}
diff --git a/vendor/gix-object/src/tag/decode.rs b/vendor/gix-object/src/tag/decode.rs
index ba9460af9..73a928638 100644
--- a/vendor/gix-object/src/tag/decode.rs
+++ b/vendor/gix-object/src/tag/decode.rs
@@ -1,90 +1,75 @@
-use nom::{
- branch::alt,
- bytes::complete::{tag, take_until, take_while, take_while1},
- character::is_alphabetic,
- combinator::{all_consuming, opt, recognize},
- error::{context, ContextError, ParseError},
- sequence::{preceded, tuple},
- IResult,
+use winnow::{
+ combinator::{alt, delimited, eof, opt, preceded, rest, terminated},
+ error::{AddContext, ParserError, StrContext},
+ prelude::*,
+ stream::AsChar,
+ token::{take_until0, take_while},
};
use crate::{parse, parse::NL, BStr, ByteSlice, TagRef};
-pub fn git_tag<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(i: &'a [u8]) -> IResult<&[u8], TagRef<'a>, E> {
- let (i, target) = context("object <40 lowercase hex char>", |i| {
- parse::header_field(i, b"object", parse::hex_hash)
- })(i)?;
-
- let (i, kind) = context("type <object kind>", |i| {
- parse::header_field(i, b"type", take_while1(is_alphabetic))
- })(i)?;
- let kind = crate::Kind::from_bytes(kind)
- .map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes)))?;
-
- let (i, tag_version) = context("tag <version>", |i| {
- parse::header_field(i, b"tag", take_while1(|b| b != NL[0]))
- })(i)?;
-
- let (i, signature) = context(
- "tagger <signature>",
- opt(|i| parse::header_field(i, b"tagger", parse::signature)),
- )(i)?;
- let (i, (message, pgp_signature)) = all_consuming(message)(i)?;
- Ok((
- i,
- TagRef {
- target,
- name: tag_version.as_bstr(),
- target_kind: kind,
- message,
- tagger: signature,
- pgp_signature,
- },
- ))
+pub fn git_tag<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
+ i: &mut &'a [u8],
+) -> PResult<TagRef<'a>, E> {
+ (
+ (|i: &mut _| parse::header_field(i, b"object", parse::hex_hash))
+ .context(StrContext::Expected("object <40 lowercase hex char>".into())),
+ (|i: &mut _| parse::header_field(i, b"type", take_while(1.., AsChar::is_alpha)))
+ .verify_map(|kind| crate::Kind::from_bytes(kind).ok())
+ .context(StrContext::Expected("type <object kind>".into())),
+ (|i: &mut _| parse::header_field(i, b"tag", take_while(1.., |b| b != NL[0])))
+ .context(StrContext::Expected("tag <version>".into())),
+ opt(|i: &mut _| parse::header_field(i, b"tagger", parse::signature))
+ .context(StrContext::Expected("tagger <signature>".into())),
+ terminated(message, eof),
+ )
+ .map(
+ |(target, kind, tag_version, signature, (message, pgp_signature))| TagRef {
+ target,
+ name: tag_version.as_bstr(),
+ target_kind: kind,
+ message,
+ tagger: signature,
+ pgp_signature,
+ },
+ )
+ .parse_next(i)
}
-pub fn message<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a BStr, Option<&'a BStr>), E> {
+pub fn message<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<(&'a BStr, Option<&'a BStr>), E> {
const PGP_SIGNATURE_BEGIN: &[u8] = b"\n-----BEGIN PGP SIGNATURE-----";
const PGP_SIGNATURE_END: &[u8] = b"-----END PGP SIGNATURE-----";
if i.is_empty() {
- return Ok((i, (i.as_bstr(), None)));
- }
- let (i, _) = tag(NL)(i)?;
- fn all_to_end<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a [u8], &'a [u8]), E> {
- if i.is_empty() {
- // Empty message. That's OK.
- return Ok((&[], (&[], &[])));
- }
- // an empty signature message signals that there is none - the function signature is needed
- // to work with 'alt(…)'. PGP signatures are never empty
- Ok((&[], (i, &[])))
+ return Ok((b"".as_bstr(), None));
}
- let (i, (message, signature)) = alt((
- tuple((
- take_until(PGP_SIGNATURE_BEGIN),
- preceded(
- tag(NL),
- recognize(tuple((
- tag(&PGP_SIGNATURE_BEGIN[1..]),
- take_until(PGP_SIGNATURE_END),
- tag(PGP_SIGNATURE_END),
- take_while(|_| true),
- ))),
+ delimited(
+ NL,
+ alt((
+ (
+ take_until0(PGP_SIGNATURE_BEGIN),
+ preceded(
+ NL,
+ (
+ &PGP_SIGNATURE_BEGIN[1..],
+ take_until0(PGP_SIGNATURE_END),
+ PGP_SIGNATURE_END,
+ rest,
+ )
+ .recognize()
+ .map(|signature: &[u8]| {
+ if signature.is_empty() {
+ None
+ } else {
+ Some(signature.as_bstr())
+ }
+ }),
+ ),
),
+ rest.map(|rest: &[u8]| (rest, None)),
)),
- all_to_end,
- ))(i)?;
- let (i, _) = opt(tag(NL))(i)?;
- Ok((
- i,
- (
- message.as_bstr(),
- if signature.is_empty() {
- None
- } else {
- Some(signature.as_bstr())
- },
- ),
- ))
+ opt(NL),
+ )
+ .map(|(message, signature)| (message.as_bstr(), signature))
+ .parse_next(i)
}
diff --git a/vendor/gix-object/src/tag/mod.rs b/vendor/gix-object/src/tag/mod.rs
index 1cd353ffb..3813bfc14 100644
--- a/vendor/gix-object/src/tag/mod.rs
+++ b/vendor/gix-object/src/tag/mod.rs
@@ -10,10 +10,8 @@ pub mod ref_iter;
impl<'a> TagRef<'a> {
/// Deserialize a tag from `data`.
- pub fn from_bytes(data: &'a [u8]) -> Result<TagRef<'a>, crate::decode::Error> {
- decode::git_tag(data)
- .map(|(_, t)| t)
- .map_err(crate::decode::Error::from)
+ pub fn from_bytes(mut data: &'a [u8]) -> Result<TagRef<'a>, crate::decode::Error> {
+ decode::git_tag(&mut data).map_err(crate::decode::Error::with_err)
}
/// The object this tag points to as `Id`.
pub fn target(&self) -> gix_hash::ObjectId {
diff --git a/vendor/gix-object/src/tag/ref_iter.rs b/vendor/gix-object/src/tag/ref_iter.rs
index 1138016b5..b3956ff83 100644
--- a/vendor/gix-object/src/tag/ref_iter.rs
+++ b/vendor/gix-object/src/tag/ref_iter.rs
@@ -1,10 +1,11 @@
use bstr::BStr;
use gix_hash::{oid, ObjectId};
-use nom::{
- bytes::complete::take_while1,
- character::is_alphabetic,
- combinator::{all_consuming, opt},
- error::{context, ParseError},
+use winnow::{
+ combinator::{eof, opt, terminated},
+ error::{ParserError, StrContext},
+ prelude::*,
+ stream::AsChar,
+ token::take_while,
};
use crate::{bstr::ByteSlice, parse, parse::NL, tag::decode, Kind, TagRefIter};
@@ -57,13 +58,21 @@ fn missing_field() -> crate::decode::Error {
}
impl<'a> TagRefIter<'a> {
+ #[inline]
fn next_inner(i: &'a [u8], state: &mut State) -> Result<(&'a [u8], Token<'a>), crate::decode::Error> {
+ Self::next_inner_(i, state).map_err(crate::decode::Error::with_err)
+ }
+
+ fn next_inner_(
+ mut i: &'a [u8],
+ state: &mut State,
+ ) -> Result<(&'a [u8], Token<'a>), winnow::error::ErrMode<crate::decode::ParseError>> {
use State::*;
Ok(match state {
Target => {
- let (i, target) = context("object <40 lowercase hex char>", |i| {
- parse::header_field(i, b"object", parse::hex_hash)
- })(i)?;
+ let target = (|i: &mut _| parse::header_field(i, b"object", parse::hex_hash))
+ .context(StrContext::Expected("object <40 lowercase hex char>".into()))
+ .parse_next(&mut i)?;
*state = TargetKind;
(
i,
@@ -73,36 +82,30 @@ impl<'a> TagRefIter<'a> {
)
}
TargetKind => {
- let (i, kind) = context("type <object kind>", |i| {
- parse::header_field(i, b"type", take_while1(is_alphabetic))
- })(i)?;
- let kind = Kind::from_bytes(kind).map_err(|_| {
- #[allow(clippy::let_unit_value)]
- {
- let err = crate::decode::ParseError::from_error_kind(i, nom::error::ErrorKind::MapRes);
- nom::Err::Error(err)
- }
- })?;
+ let kind = (|i: &mut _| parse::header_field(i, b"type", take_while(1.., AsChar::is_alpha)))
+ .context(StrContext::Expected("type <object kind>".into()))
+ .parse_next(&mut i)?;
+ let kind = Kind::from_bytes(kind)
+ .map_err(|_| winnow::error::ErrMode::from_error_kind(&i, winnow::error::ErrorKind::Verify))?;
*state = Name;
(i, Token::TargetKind(kind))
}
Name => {
- let (i, tag_version) = context("tag <version>", |i| {
- parse::header_field(i, b"tag", take_while1(|b| b != NL[0]))
- })(i)?;
+ let tag_version = (|i: &mut _| parse::header_field(i, b"tag", take_while(1.., |b| b != NL[0])))
+ .context(StrContext::Expected("tag <version>".into()))
+ .parse_next(&mut i)?;
*state = Tagger;
(i, Token::Name(tag_version.as_bstr()))
}
Tagger => {
- let (i, signature) = context(
- "tagger <signature>",
- opt(|i| parse::header_field(i, b"tagger", parse::signature)),
- )(i)?;
+ let signature = opt(|i: &mut _| parse::header_field(i, b"tagger", parse::signature))
+ .context(StrContext::Expected("tagger <signature>".into()))
+ .parse_next(&mut i)?;
*state = Message;
(i, Token::Tagger(signature))
}
Message => {
- let (i, (message, pgp_signature)) = all_consuming(decode::message)(i)?;
+ let (message, pgp_signature) = terminated(decode::message, eof).parse_next(&mut i)?;
debug_assert!(
i.is_empty(),
"we should have consumed all data - otherwise iter may go forever"
diff --git a/vendor/gix-object/src/tag/write.rs b/vendor/gix-object/src/tag/write.rs
index 5f6d58c86..cee9e587c 100644
--- a/vendor/gix-object/src/tag/write.rs
+++ b/vendor/gix-object/src/tag/write.rs
@@ -21,12 +21,12 @@ impl From<Error> for io::Error {
}
impl crate::WriteTo for Tag {
- fn write_to(&self, mut out: impl io::Write) -> io::Result<()> {
- encode::trusted_header_id(b"object", &self.target, &mut out)?;
- encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?;
- encode::header_field(b"tag", validated_name(self.name.as_ref())?, &mut out)?;
+ fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
+ encode::trusted_header_id(b"object", &self.target, out)?;
+ encode::trusted_header_field(b"type", self.target_kind.as_bytes(), out)?;
+ encode::header_field(b"tag", validated_name(self.name.as_ref())?, out)?;
if let Some(tagger) = &self.tagger {
- encode::trusted_header_signature(b"tagger", &tagger.to_ref(), &mut out)?;
+ encode::trusted_header_signature(b"tagger", &tagger.to_ref(), out)?;
}
out.write_all(NL)?;
@@ -58,7 +58,7 @@ impl crate::WriteTo for Tag {
}
impl<'a> crate::WriteTo for TagRef<'a> {
- fn write_to(&self, mut out: impl io::Write) -> io::Result<()> {
+ fn write_to(&self, mut out: &mut dyn io::Write) -> io::Result<()> {
encode::trusted_header_field(b"object", self.target, &mut out)?;
encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?;
encode::header_field(b"tag", validated_name(self.name)?, &mut out)?;
diff --git a/vendor/gix-object/src/traits.rs b/vendor/gix-object/src/traits.rs
index 193cd78c3..c0c4adee2 100644
--- a/vendor/gix-object/src/traits.rs
+++ b/vendor/gix-object/src/traits.rs
@@ -5,7 +5,7 @@ use crate::Kind;
/// Writing of objects to a `Write` implementation
pub trait WriteTo {
/// Write a representation of this instance to `out`.
- fn write_to(&self, out: impl std::io::Write) -> std::io::Result<()>;
+ fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()>;
/// Returns the type of this object.
fn kind(&self) -> Kind;
@@ -29,15 +29,15 @@ impl<T> WriteTo for &T
where
T: WriteTo,
{
- fn write_to(&self, out: impl Write) -> std::io::Result<()> {
+ fn write_to(&self, out: &mut dyn Write) -> std::io::Result<()> {
<T as WriteTo>::write_to(self, out)
}
- fn size(&self) -> usize {
- <T as WriteTo>::size(self)
- }
-
fn kind(&self) -> Kind {
<T as WriteTo>::kind(self)
}
+
+ fn size(&self) -> usize {
+ <T as WriteTo>::size(self)
+ }
}
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();