Skip to content

Commit f826271

Browse files
committed
feat: use winnow instead of nom
Winnow provides a similar, and arguably cleaner, combinator-based parsing capability as nom. Using winnow reduces the number of dependencies by one. Nom was only used by StGit, but winnow is also used by gix for its parsing needs, and was thus already a transitive dependency.
1 parent e666bf8 commit f826271

19 files changed

+558
-412
lines changed

Cargo.lock

Lines changed: 1 addition & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ flate2 = "1"
4040
gix = { version = "0.64", default-features = false, features = ["command", "revision"] }
4141
indexmap = "2.1"
4242
is-terminal = "0.4"
43-
nom = { version = "7", default-features = false, features = ["std"] }
4443
serde = { version = "1.0", features = ["derive"] }
4544
serde_json = "1.0"
4645
strsim = "0.11"
@@ -54,6 +53,7 @@ time = { version = "0.3.31", default-features = false, features = [
5453
"macros",
5554
"parsing",
5655
] }
56+
winnow = "0.6.18"
5757

5858
curl = { version = "0.4", optional = true }
5959

src/branchloc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ impl FromStr for BranchLocator {
3636
type Err = anyhow::Error;
3737

3838
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
39-
use nom::combinator::{all_consuming, complete};
40-
complete(all_consuming(crate::patch::parse::branch_locator))(s)
41-
.map(|(_, loc)| loc)
39+
use winnow::Parser;
40+
crate::patch::parse::branch_locator
41+
.parse(s)
4242
.map_err(|_| anyhow::anyhow!("invalid branch locator `{s}`"))
4343
}
4444
}

src/patch/locator.rs

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ impl FromStr for PatchLocator {
5656
type Err = Error;
5757

5858
fn from_str(s: &str) -> Result<Self, Self::Err> {
59-
use nom::combinator::{all_consuming, complete};
60-
complete(all_consuming(super::parse::patch_locator))(s)
61-
.map(|(_, location)| location)
59+
use winnow::Parser;
60+
super::parse::patch_locator
61+
.parse(s)
6262
.map_err(|_| Error::InvalidPatchLocator(s.to_string()))
6363
}
6464
}
@@ -412,32 +412,12 @@ impl PatchLocator {
412412
offsets: self.offsets.clone(),
413413
},
414414
PatchId::Name(patchname) => {
415-
use nom::combinator::{all_consuming, complete};
416-
let patch_offsets = |s| {
417-
complete(all_consuming(super::parse::patch_offsets))(s)
418-
.map(|(_, output)| output)
419-
.ok()
420-
};
421-
let oid_prefix_offsets = |s| {
422-
complete(all_consuming(super::parse::oid_prefix_offsets))(s)
423-
.map(|(_, output)| output)
424-
.ok()
425-
};
426-
let sign_number_offsets = |s| {
427-
complete(all_consuming(super::parse::sign_number_offsets))(s)
428-
.map(|(_, output)| output)
429-
.ok()
430-
};
431-
let patch_locator_top = |s| {
432-
complete(all_consuming(super::parse::patch_locator_top))(s)
433-
.map(|(_, output)| output)
434-
.ok()
435-
};
436-
let patch_locator_base = |s| {
437-
complete(all_consuming(super::parse::patch_locator_base))(s)
438-
.map(|(_, output)| output)
439-
.ok()
440-
};
415+
use winnow::Parser;
416+
let patch_offsets = |s| super::parse::patch_offsets.parse(s).ok();
417+
let oid_prefix_offsets = |s| super::parse::oid_prefix_offsets.parse(s).ok();
418+
let sign_number_offsets = |s| super::parse::sign_number_offsets.parse(s).ok();
419+
let patch_locator_top = |s| super::parse::patch_locator_top.parse(s).ok();
420+
let patch_locator_base = |s| super::parse::patch_locator_base.parse(s).ok();
441421

442422
let name: &str = patchname.as_ref();
443423

src/patch/offset.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
55
use std::{fmt::Write, str::FromStr};
66

7+
use winnow::Parser;
8+
79
use super::{PatchOffsetAtom, PatchOffsets};
810

911
#[derive(thiserror::Error, Debug)]
@@ -36,9 +38,9 @@ impl FromStr for PatchOffsets {
3638
type Err = Error;
3739

3840
fn from_str(s: &str) -> Result<Self, Self::Err> {
39-
use nom::combinator::{all_consuming, complete};
40-
complete(all_consuming(super::parse::patch_offsets))(s)
41-
.map(|(_, offsets)| offsets)
41+
use winnow::Parser;
42+
super::parse::patch_offsets
43+
.parse(s)
4244
.map_err(|_| Error::InvalidPatchOffsets(s.to_string()))
4345
}
4446
}
@@ -62,7 +64,8 @@ impl PatchOffsets {
6264

6365
/// Construct constituent [`PatchOffsetAtom`] instances.
6466
pub(super) fn atoms(&self) -> Vec<PatchOffsetAtom> {
65-
super::parse::patch_offset_atoms(&self.0)
67+
super::parse::patch_offset_atoms
68+
.parse_peek(&self.0)
6669
.expect("previously validated")
6770
.1
6871
}

src/patch/parse/locator.rs

Lines changed: 66 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22

33
//! Parsing support for [`PatchLocator`].
44
5-
use nom::{
6-
branch::alt,
7-
bytes::complete::tag,
8-
character::complete::{char as the_char, hex_digit1},
9-
combinator::{map, map_res, opt, recognize},
10-
multi::{many0, many0_count},
11-
sequence::tuple,
5+
use winnow::{
6+
ascii::hex_digit1,
7+
combinator::{alt, opt, repeat},
8+
PResult, Parser,
129
};
1310

1411
use super::{
@@ -18,115 +15,106 @@ use super::{
1815
};
1916
use crate::patch::{PatchId, PatchLocator, PatchOffsetAtom, PatchOffsets};
2017

21-
pub(in super::super) fn patch_locator(input: &str) -> nom::IResult<&str, PatchLocator> {
18+
pub(in super::super) fn patch_locator(input: &mut &str) -> PResult<PatchLocator> {
2219
alt((
2320
patch_locator_name,
2421
patch_locator_from_last,
2522
patch_locator_top,
2623
patch_locator_base,
27-
))(input)
24+
))
25+
.parse_next(input)
2826
}
2927

30-
fn patch_locator_name(input: &str) -> nom::IResult<&str, PatchLocator> {
31-
map(
32-
tuple((patch_name, patch_offsets)),
33-
|(patchname, offsets)| PatchLocator {
28+
fn patch_locator_name(input: &mut &str) -> PResult<PatchLocator> {
29+
(patch_name, patch_offsets)
30+
.map(|(patchname, offsets)| PatchLocator {
3431
id: PatchId::Name(patchname),
3532
offsets,
36-
},
37-
)(input)
33+
})
34+
.parse_next(input)
3835
}
3936

40-
fn patch_locator_from_last(input: &str) -> nom::IResult<&str, PatchLocator> {
41-
map(
42-
tuple((the_char('^'), opt(nonplussed_int), patch_offsets)),
43-
|(_, below_last, offsets)| PatchLocator {
37+
fn patch_locator_from_last(input: &mut &str) -> PResult<PatchLocator> {
38+
('^', opt(nonplussed_int), patch_offsets)
39+
.map(|(_, below_last, offsets)| PatchLocator {
4440
id: PatchId::BelowLast(below_last),
4541
offsets,
46-
},
47-
)(input)
42+
})
43+
.parse_next(input)
4844
}
4945

50-
pub(in super::super) fn patch_locator_top(input: &str) -> nom::IResult<&str, PatchLocator> {
46+
pub(in super::super) fn patch_locator_top(input: &mut &str) -> PResult<PatchLocator> {
5147
alt((
52-
map(tuple((the_char('@'), patch_offsets)), |(_, offsets)| {
53-
PatchLocator {
54-
id: PatchId::Top,
55-
offsets,
56-
}
48+
('@', patch_offsets).map(|(_, offsets)| PatchLocator {
49+
id: PatchId::Top,
50+
offsets,
51+
}),
52+
('~', opt(unsigned_int), patch_offsets).map(|(_, n, offsets)| PatchLocator {
53+
id: PatchId::BelowTop(n),
54+
offsets,
5755
}),
58-
map(
59-
tuple((the_char('~'), opt(unsigned_int), patch_offsets)),
60-
|(_, n, offsets)| PatchLocator {
61-
id: PatchId::BelowTop(n),
62-
offsets,
63-
},
64-
),
65-
))(input)
56+
))
57+
.parse_next(input)
6658
}
6759

68-
pub(in super::super) fn patch_locator_base(input: &str) -> nom::IResult<&str, PatchLocator> {
69-
map(tuple((tag("{base}"), patch_offsets)), |(_, offsets)| {
70-
PatchLocator {
60+
pub(in super::super) fn patch_locator_base(input: &mut &str) -> PResult<PatchLocator> {
61+
("{base}", patch_offsets)
62+
.map(|(_, offsets)| PatchLocator {
7163
id: PatchId::Base,
7264
offsets,
73-
}
74-
})(input)
65+
})
66+
.parse_next(input)
7567
}
7668

77-
pub(in super::super) fn patch_offsets(input: &str) -> nom::IResult<&str, PatchOffsets> {
78-
map(recognize(many0_count(patch_offset_atom)), |s| {
79-
PatchOffsets(String::from(s))
80-
})(input)
69+
pub(in super::super) fn patch_offsets(input: &mut &str) -> PResult<PatchOffsets> {
70+
repeat::<_, _, Vec<PatchOffsetAtom>, _, _>(0.., patch_offset_atom)
71+
.take()
72+
.map(|s: &str| PatchOffsets(s.to_string()))
73+
.parse_next(input)
8174
}
8275

83-
pub(in super::super) fn patch_offset_atoms(
84-
input: &str,
85-
) -> nom::IResult<&str, Vec<PatchOffsetAtom>> {
86-
many0(patch_offset_atom)(input)
76+
pub(in super::super) fn patch_offset_atoms(input: &mut &str) -> PResult<Vec<PatchOffsetAtom>> {
77+
repeat(0.., patch_offset_atom).parse_next(input)
8778
}
8879

89-
pub(in super::super) fn patch_offset_atom(input: &str) -> nom::IResult<&str, PatchOffsetAtom> {
90-
alt((patch_offset_atom_plus, patch_offset_atom_tilde))(input)
80+
pub(in super::super) fn patch_offset_atom(input: &mut &str) -> PResult<PatchOffsetAtom> {
81+
alt((patch_offset_atom_plus, patch_offset_atom_tilde)).parse_next(input)
9182
}
9283

93-
fn patch_offset_atom_plus(input: &str) -> nom::IResult<&str, PatchOffsetAtom> {
94-
map(tuple((the_char('+'), opt(unsigned_int))), |(_, n)| {
95-
PatchOffsetAtom::Plus(n)
96-
})(input)
84+
fn patch_offset_atom_plus(input: &mut &str) -> PResult<PatchOffsetAtom> {
85+
('+', opt(unsigned_int))
86+
.map(|(_, n)| PatchOffsetAtom::Plus(n))
87+
.parse_next(input)
9788
}
9889

99-
fn patch_offset_atom_tilde(input: &str) -> nom::IResult<&str, PatchOffsetAtom> {
100-
map(tuple((the_char('~'), opt(unsigned_int))), |(_, n)| {
101-
PatchOffsetAtom::Tilde(n)
102-
})(input)
90+
fn patch_offset_atom_tilde(input: &mut &str) -> PResult<PatchOffsetAtom> {
91+
('~', opt(unsigned_int))
92+
.map(|(_, n)| PatchOffsetAtom::Tilde(n))
93+
.parse_next(input)
10394
}
10495

10596
pub(in super::super) fn oid_prefix_offsets(
106-
input: &str,
107-
) -> nom::IResult<&str, (gix::hash::Prefix, PatchOffsets)> {
108-
tuple((oid_prefix, patch_offsets))(input)
97+
input: &mut &str,
98+
) -> PResult<(gix::hash::Prefix, PatchOffsets)> {
99+
(oid_prefix, patch_offsets).parse_next(input)
109100
}
110101

111-
fn oid_prefix(input: &str) -> nom::IResult<&str, gix::hash::Prefix> {
112-
map_res(hex_digit1, gix::hash::Prefix::from_hex)(input)
102+
fn oid_prefix(input: &mut &str) -> PResult<gix::hash::Prefix> {
103+
hex_digit1
104+
.try_map(gix::hash::Prefix::from_hex)
105+
.parse_next(input)
113106
}
114107

115108
pub(in super::super) fn sign_number_offsets(
116-
input: &str,
117-
) -> nom::IResult<&str, (Option<Sign>, Option<usize>, PatchOffsets)> {
109+
input: &mut &str,
110+
) -> PResult<(Option<Sign>, Option<usize>, PatchOffsets)> {
118111
alt((
119-
map(tuple((negative_int, patch_offsets)), |(n, offsets)| {
120-
(Some(Sign::Minus), Some(n.unsigned_abs()), offsets)
121-
}),
122-
map(tuple((plusative_int, patch_offsets)), |(n, offsets)| {
123-
(Some(Sign::Plus), Some(n.unsigned_abs()), offsets)
124-
}),
125-
map(tuple((unsigned_int, patch_offsets)), |(n, offsets)| {
126-
(None, Some(n), offsets)
127-
}),
128-
map(tuple((sign, patch_offsets)), |(sign, offsets)| {
129-
(Some(sign), None, offsets)
130-
}),
131-
))(input)
112+
(negative_int, patch_offsets)
113+
.map(|(n, offsets)| (Some(Sign::Minus), Some(n.unsigned_abs()), offsets)),
114+
(plusative_int, patch_offsets)
115+
.map(|(n, offsets)| (Some(Sign::Plus), Some(n.unsigned_abs()), offsets)),
116+
(unsigned_int, patch_offsets).map(|(n, offsets)| (None, Some(n), offsets)),
117+
(sign, patch_offsets).map(|(sign, offsets)| (Some(sign), None, offsets)),
118+
))
119+
.parse_next(input)
132120
}

src/patch/parse/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22

3-
//! Parsers for patch and revision specifications using [`nom`].
3+
//! Parsers for patch and revision specifications using [`winnow`].
44
55
mod locator;
66
mod name;

0 commit comments

Comments
 (0)