eml_codec/imf/
mime.rs

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}