Skip to main content

eml_codec/imf/
mime.rs

1#[cfg(feature = "arbitrary")]
2use arbitrary::Arbitrary;
3use bounded_static::ToStatic;
4use nom::{
5    bytes::complete::tag,
6    character::complete::digit1,
7    combinator::{map, opt},
8    sequence::tuple,
9    IResult,
10};
11
12#[cfg(feature = "arbitrary")]
13use crate::fuzz_eq::FuzzEq;
14use crate::i18n::ContainsUtf8;
15use crate::print::{Formatter, Print, ToStringFromPrint};
16use crate::text::whitespace::cfws;
17use eml_codec_derives::instrument_input;
18
19#[derive(Clone, ContainsUtf8, Debug, PartialEq, ToStatic, ToStringFromPrint)]
20#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
21#[contains_utf8(false)]
22pub struct Version {
23    pub major: u64,
24    pub minor: u64,
25}
26
27impl Default for Version {
28    fn default() -> Self {
29        Self { major: 1, minor: 0 }
30    }
31}
32#[cfg(feature = "arbitrary")]
33impl FuzzEq for Version {
34    fn fuzz_eq(&self, other: &Self) -> bool {
35        self == other
36    }
37}
38
39#[instrument_input("tracing")]
40pub fn version(input: &[u8]) -> IResult<&[u8], Version> {
41    let (rest, (_, major, _, _, _, minor, _)) = tuple((
42        opt(cfws),
43        map(digit1, ascii_to_u64),
44        opt(cfws),
45        tag(b"."),
46        opt(cfws),
47        map(digit1, ascii_to_u64),
48        opt(cfws),
49    ))(input)?;
50    Ok((rest, Version { major, minor }))
51}
52
53fn ascii_to_u64(c: &[u8]) -> u64 {
54    str::from_utf8(c).unwrap().parse().unwrap()
55}
56
57impl Print for Version {
58    fn print(&self, fmt: &mut impl Formatter) {
59        fmt.write_bytes(self.major.to_string().as_bytes());
60        fmt.write_bytes(b".");
61        fmt.write_bytes(self.minor.to_string().as_bytes())
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_version() {
71        assert_eq!(
72            version(b"1.0"),
73            Ok((&b""[..], Version { major: 1, minor: 0 })),
74        );
75
76        assert_eq!(
77            version(b" 1.0 (produced by MetaSend Vx.x)"),
78            Ok((&b""[..], Version { major: 1, minor: 0 })),
79        );
80
81        assert_eq!(
82            version(b"(produced by MetaSend Vx.x) 1.0"),
83            Ok((&b""[..], Version { major: 1, minor: 0 })),
84        );
85
86        assert_eq!(
87            version(b"1.(produced by MetaSend Vx.x)0"),
88            Ok((&b""[..], Version { major: 1, minor: 0 })),
89        );
90    }
91}