1use nom::{
2 bytes::complete::{tag, take},
3 combinator::{map, opt, verify},
4 sequence::tuple,
5 IResult,
6};
7
8use crate::text::ascii;
9use crate::text::whitespace::cfws;
10
11#[derive(Debug, PartialEq)]
12pub struct Version {
13 pub major: u8,
14 pub minor: u8,
15}
16
17pub fn version(input: &[u8]) -> IResult<&[u8], Version> {
18 let (rest, (_, major, _, _, _, minor, _)) = tuple((
19 opt(cfws),
20 map(verify(take(1usize), is_digit), ascii_to_u8),
21 opt(cfws),
22 tag(b"."),
23 opt(cfws),
24 map(verify(take(1usize), is_digit), ascii_to_u8),
25 opt(cfws),
26 ))(input)?;
27 Ok((rest, Version { major, minor }))
28}
29
30fn is_digit(c: &[u8]) -> bool {
31 c[0] >= ascii::N0 && c[0] <= ascii::N9
32}
33
34fn ascii_to_u8(c: &[u8]) -> u8 {
35 c[0] - ascii::N0
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn test_version() {
44 assert_eq!(
45 version(b"1.0"),
46 Ok((&b""[..], Version { major: 1, minor: 0 })),
47 );
48
49 assert_eq!(
50 version(b" 1.0 (produced by MetaSend Vx.x)"),
51 Ok((&b""[..], Version { major: 1, minor: 0 })),
52 );
53
54 assert_eq!(
55 version(b"(produced by MetaSend Vx.x) 1.0"),
56 Ok((&b""[..], Version { major: 1, minor: 0 })),
57 );
58
59 assert_eq!(
60 version(b"1.(produced by MetaSend Vx.x)0"),
61 Ok((&b""[..], Version { major: 1, minor: 0 })),
62 );
63 }
64}