Skip to content

Commit dd82faa

Browse files
committed
feat: Implement parsing without nom
1 parent 128f482 commit dd82faa

File tree

6 files changed

+168
-137
lines changed

6 files changed

+168
-137
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [unreleased]
99

10+
### Changed
11+
12+
- Remove `num-traits` dependency
13+
- Update all dependencies
14+
- Use `tokio` in examples
15+
1016
## [0.3.6] - 2022-12-16
1117

1218
### Changed

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ repository = "https://github.com/oblique/async-tftp-rs"
1515
[dependencies]
1616
bytes = "1.5.0"
1717
log = "0.4.20"
18-
nom = "7.1.3"
1918
thiserror = "1.0.48"
2019

2120
async-executor = "1.5.1"

src/error.rs

-6
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,3 @@ pub enum Error {
2424
#[error("Max send retries reached (peer: {0}, block id: {1})")]
2525
MaxSendRetriesReached(std::net::SocketAddr, u16),
2626
}
27-
28-
impl From<nom::Err<nom::error::Error<&[u8]>>> for Error {
29-
fn from(_error: nom::Err<nom::error::Error<&[u8]>>) -> Error {
30-
Error::InvalidPacket
31-
}
32-
}

src/packet.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
///! Packet definitions.
1+
//! Packet definitions.
22
use bytes::{BufMut, Bytes, BytesMut};
33
use std::convert::From;
44
use std::io;

src/parse.rs

+153-121
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,192 @@
1-
use nom::branch::alt;
2-
use nom::bytes::complete::{tag, tag_no_case, take_till};
3-
use nom::combinator::{map, map_opt, map_res, rest};
4-
use nom::multi::many0;
5-
use nom::number::complete::be_u16;
6-
use nom::sequence::tuple;
7-
use nom::IResult;
1+
use std::convert::TryInto;
82
use std::str::{self, FromStr};
93

10-
use crate::error::Result;
11-
use crate::packet::{self, *};
12-
13-
#[derive(Debug)]
14-
enum Opt<'a> {
15-
BlkSize(u16),
16-
Timeout(u8),
17-
Tsize(u64),
18-
Invalid(&'a str, &'a str),
19-
}
4+
use crate::error::{Error, Result};
5+
use crate::packet::{
6+
Error as PacketError, Mode, Opts, Packet, PacketType, RwReq,
7+
};
208

219
pub(crate) fn parse_packet(input: &[u8]) -> Result<Packet> {
22-
let (rest, packet) = match parse_packet_type(input)? {
23-
(data, PacketType::Rrq) => parse_rrq(data)?,
24-
(data, PacketType::Wrq) => parse_wrq(data)?,
25-
(data, PacketType::Data) => parse_data(data)?,
26-
(data, PacketType::Ack) => parse_ack(data)?,
27-
(data, PacketType::Error) => parse_error(data)?,
28-
(data, PacketType::OAck) => parse_oack(data)?,
29-
};
30-
31-
if rest.is_empty() {
32-
Ok(packet)
33-
} else {
34-
Err(crate::Error::InvalidPacket)
35-
}
36-
}
37-
38-
fn nul_str(input: &[u8]) -> IResult<&[u8], &str> {
39-
map_res(
40-
tuple((take_till(|c| c == b'\0'), tag(b"\0"))),
41-
|(s, _): (&[u8], _)| str::from_utf8(s),
42-
)(input)
10+
parse_packet_type(input)
11+
.and_then(|(packet_type, data)| match packet_type {
12+
PacketType::Rrq => parse_rrq(data),
13+
PacketType::Wrq => parse_wrq(data),
14+
PacketType::Data => parse_data(data),
15+
PacketType::Ack => parse_ack(data),
16+
PacketType::Error => parse_error(data),
17+
PacketType::OAck => parse_oack(data),
18+
})
19+
.ok_or(Error::InvalidPacket)
4320
}
4421

45-
fn parse_packet_type(input: &[u8]) -> IResult<&[u8], PacketType> {
46-
map_opt(be_u16, PacketType::from_u16)(input)
22+
fn parse_nul_str(input: &[u8]) -> Option<(&str, &[u8])> {
23+
let pos = input.iter().position(|c| *c == b'\0')?;
24+
let s = str::from_utf8(&input[..pos]).ok()?;
25+
Some((s, &input[pos + 1..]))
4726
}
4827

49-
fn parse_mode(input: &[u8]) -> IResult<&[u8], Mode> {
50-
alt((
51-
map(tag_no_case(b"netascii\0"), |_| Mode::Netascii),
52-
map(tag_no_case(b"octet\0"), |_| Mode::Octet),
53-
map(tag_no_case(b"mail\0"), |_| Mode::Mail),
54-
))(input)
28+
fn parse_u16_be(input: &[u8]) -> Option<(u16, &[u8])> {
29+
let bytes = input.get(..2)?;
30+
let num = u16::from_be_bytes(bytes.try_into().ok()?);
31+
Some((num, &input[2..]))
5532
}
5633

57-
fn parse_opt_blksize(input: &[u8]) -> IResult<&[u8], Opt> {
58-
map_opt(tuple((tag_no_case(b"blksize\0"), nul_str)), |(_, n): (_, &str)| {
59-
u16::from_str(n)
60-
.ok()
61-
.filter(|n| *n >= 8 && *n <= 65464)
62-
.map(Opt::BlkSize)
63-
})(input)
34+
fn parse_packet_type(input: &[u8]) -> Option<(PacketType, &[u8])> {
35+
let (num, rest) = parse_u16_be(input)?;
36+
let val = PacketType::from_u16(num)?;
37+
Some((val, rest))
6438
}
6539

66-
fn parse_opt_timeout(input: &[u8]) -> IResult<&[u8], Opt> {
67-
map_opt(tuple((tag_no_case(b"timeout\0"), nul_str)), |(_, n): (_, &str)| {
68-
u8::from_str(n).ok().filter(|n| *n >= 1).map(Opt::Timeout)
69-
})(input)
70-
}
40+
fn parse_mode(input: &[u8]) -> Option<(Mode, &[u8])> {
41+
let (s, rest) = parse_nul_str(input)?;
7142

72-
fn parse_opt_tsize(input: &[u8]) -> IResult<&[u8], Opt> {
73-
map_opt(tuple((tag_no_case(b"tsize\0"), nul_str)), |(_, n): (_, &str)| {
74-
u64::from_str(n).ok().map(Opt::Tsize)
75-
})(input)
76-
}
43+
let mode = if s.eq_ignore_ascii_case("netascii") {
44+
Mode::Netascii
45+
} else if s.eq_ignore_ascii_case("octet") {
46+
Mode::Octet
47+
} else if s.eq_ignore_ascii_case("mail") {
48+
Mode::Mail
49+
} else {
50+
return None;
51+
};
7752

78-
pub(crate) fn parse_opts(input: &[u8]) -> IResult<&[u8], Opts> {
79-
many0(alt((
80-
parse_opt_blksize,
81-
parse_opt_timeout,
82-
parse_opt_tsize,
83-
map(tuple((nul_str, nul_str)), |(k, v)| Opt::Invalid(k, v)),
84-
)))(input)
85-
.map(|(i, opt_vec)| (i, to_opts(opt_vec)))
53+
Some((mode, rest))
8654
}
8755

88-
fn to_opts(opt_vec: Vec<Opt>) -> Opts {
56+
pub(crate) fn parse_opts(mut input: &[u8]) -> Option<Opts> {
8957
let mut opts = Opts::default();
9058

91-
for opt in opt_vec {
92-
match opt {
93-
Opt::BlkSize(size) => {
94-
if opts.block_size.is_none() {
95-
opts.block_size.replace(size);
59+
while !input.is_empty() {
60+
let (name, rest) = parse_nul_str(input)?;
61+
let (val, rest) = parse_nul_str(rest)?;
62+
63+
if name.eq_ignore_ascii_case("blksize") {
64+
if let Ok(val) = u16::from_str(val) {
65+
if val >= 8 && val <= 65464 {
66+
opts.block_size = Some(val);
9667
}
9768
}
98-
Opt::Timeout(timeout) => {
99-
if opts.timeout.is_none() {
100-
opts.timeout.replace(timeout);
69+
} else if name.eq_ignore_ascii_case("timeout") {
70+
if let Ok(val) = u8::from_str(val) {
71+
if val >= 1 {
72+
opts.timeout = Some(val);
10173
}
10274
}
103-
Opt::Tsize(size) => {
104-
if opts.transfer_size.is_none() {
105-
opts.transfer_size.replace(size);
106-
}
75+
} else if name.eq_ignore_ascii_case("tsize") {
76+
if let Ok(val) = u64::from_str(val) {
77+
opts.transfer_size = Some(val);
10778
}
108-
Opt::Invalid(..) => {}
10979
}
80+
81+
input = rest;
11082
}
11183

112-
opts
84+
Some(opts)
85+
}
86+
87+
fn parse_rrq(input: &[u8]) -> Option<Packet> {
88+
let (filename, rest) = parse_nul_str(input)?;
89+
let (mode, rest) = parse_mode(rest)?;
90+
let opts = parse_opts(rest)?;
91+
92+
Some(Packet::Rrq(RwReq {
93+
filename: filename.to_owned(),
94+
mode,
95+
opts,
96+
}))
11397
}
11498

115-
fn parse_rrq(input: &[u8]) -> IResult<&[u8], Packet> {
116-
let (input, (filename, mode, opts)) =
117-
tuple((nul_str, parse_mode, parse_opts))(input)?;
118-
119-
Ok((
120-
input,
121-
Packet::Rrq(RwReq {
122-
filename: filename.to_owned(),
123-
mode,
124-
opts,
125-
}),
126-
))
99+
fn parse_wrq(input: &[u8]) -> Option<Packet> {
100+
let (filename, rest) = parse_nul_str(input)?;
101+
let (mode, rest) = parse_mode(rest)?;
102+
let opts = parse_opts(rest)?;
103+
104+
Some(Packet::Wrq(RwReq {
105+
filename: filename.to_owned(),
106+
mode,
107+
opts,
108+
}))
127109
}
128110

129-
fn parse_wrq(input: &[u8]) -> IResult<&[u8], Packet> {
130-
let (input, (filename, mode, opts)) =
131-
tuple((nul_str, parse_mode, parse_opts))(input)?;
132-
133-
Ok((
134-
input,
135-
Packet::Wrq(RwReq {
136-
filename: filename.to_owned(),
137-
mode,
138-
opts,
139-
}),
140-
))
111+
fn parse_data(input: &[u8]) -> Option<Packet> {
112+
let (block_nr, rest) = parse_u16_be(input)?;
113+
Some(Packet::Data(block_nr, rest))
141114
}
142115

143-
fn parse_data(input: &[u8]) -> IResult<&[u8], Packet> {
144-
tuple((be_u16, rest))(input)
145-
.map(|(i, (block_nr, data))| (i, Packet::Data(block_nr, data)))
116+
fn parse_ack(input: &[u8]) -> Option<Packet> {
117+
let (block_nr, rest) = parse_u16_be(input)?;
118+
119+
if !rest.is_empty() {
120+
return None;
121+
}
122+
123+
Some(Packet::Ack(block_nr))
146124
}
147125

148-
fn parse_ack(input: &[u8]) -> IResult<&[u8], Packet> {
149-
be_u16(input).map(|(i, block_nr)| (i, Packet::Ack(block_nr)))
126+
fn parse_error(input: &[u8]) -> Option<Packet> {
127+
let (code, rest) = parse_u16_be(input)?;
128+
let (msg, rest) = parse_nul_str(rest)?;
129+
130+
if !rest.is_empty() {
131+
return None;
132+
}
133+
134+
Some(Packet::Error(PacketError::from_code(code, Some(msg))))
150135
}
151136

152-
fn parse_error(input: &[u8]) -> IResult<&[u8], Packet> {
153-
tuple((be_u16, nul_str))(input).map(|(i, (code, msg))| {
154-
(i, packet::Error::from_code(code, Some(msg)).into())
155-
})
137+
fn parse_oack(input: &[u8]) -> Option<Packet> {
138+
let opts = parse_opts(input)?;
139+
Some(Packet::OAck(opts))
156140
}
157141

158-
fn parse_oack(input: &[u8]) -> IResult<&[u8], Packet> {
159-
parse_opts(input).map(|(i, opts)| (i, Packet::OAck(opts)))
142+
#[cfg(test)]
143+
mod tests {
144+
use super::*;
145+
146+
#[test]
147+
fn nul_str() {
148+
let (s, rest) = parse_nul_str(b"123\0").unwrap();
149+
assert_eq!(s, "123");
150+
assert!(rest.is_empty());
151+
152+
let (s, rest) = parse_nul_str(b"123\0\0").unwrap();
153+
assert_eq!(s, "123");
154+
assert_eq!(rest, b"\0");
155+
156+
let (s1, rest) = parse_nul_str(b"123\0abc\0\xff\xff").unwrap();
157+
let (s2, rest) = parse_nul_str(rest).unwrap();
158+
assert_eq!(s1, "123");
159+
assert_eq!(s2, "abc");
160+
assert_eq!(rest, b"\xff\xff");
161+
162+
let (s1, rest) = parse_nul_str(b"\0\0").unwrap();
163+
let (s2, rest) = parse_nul_str(rest).unwrap();
164+
assert_eq!(s1, "");
165+
assert_eq!(s2, "");
166+
assert!(rest.is_empty());
167+
168+
assert!(parse_nul_str(b"").is_none());
169+
assert!(parse_nul_str(b"123").is_none());
170+
assert!(parse_nul_str(b"123\xff\xff\0").is_none());
171+
}
172+
173+
#[test]
174+
fn u16_be() {
175+
let (n, rest) = parse_u16_be(b"\x11\x22").unwrap();
176+
assert_eq!(n, 0x1122);
177+
assert!(rest.is_empty());
178+
179+
let (n, rest) = parse_u16_be(b"\x11\x22\x33").unwrap();
180+
assert_eq!(n, 0x1122);
181+
assert_eq!(rest, b"\x33");
182+
183+
let (n1, rest) = parse_u16_be(b"\x11\x22\x33\x44\x55").unwrap();
184+
let (n2, rest) = parse_u16_be(rest).unwrap();
185+
assert_eq!(n1, 0x1122);
186+
assert_eq!(n2, 0x3344);
187+
assert_eq!(rest, b"\x55");
188+
189+
assert!(parse_u16_be(b"").is_none());
190+
assert!(parse_u16_be(b"\x11").is_none());
191+
}
160192
}

0 commit comments

Comments
 (0)