1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use abnf_core::streaming::SP;
use nom::{
    bytes::streaming::tag,
    sequence::{delimited, tuple},
    IResult,
};

use crate::{
    parse::core::nstring,
    types::{address::Address, core::nstr},
};

/// address = "(" addr-name SP
///               addr-adl SP
///               addr-mailbox SP
///               addr-host ")"
pub(crate) fn address(input: &[u8]) -> IResult<&[u8], Address> {
    let mut parser = delimited(
        tag(b"("),
        tuple((addr_name, SP, addr_adl, SP, addr_mailbox, SP, addr_host)),
        tag(b")"),
    );

    let (remaining, (name, _, adl, _, mailbox, _, host)) = parser(input)?;

    Ok((
        remaining,
        Address::new(
            name.to_owned(),
            adl.to_owned(),
            mailbox.to_owned(),
            host.to_owned(),
        ),
    ))
}

#[inline]
/// addr-name = nstring
///
/// If non-NIL, holds phrase from [RFC-2822]
/// mailbox after removing [RFC-2822] quoting
fn addr_name(input: &[u8]) -> IResult<&[u8], nstr> {
    nstring(input)
}

#[inline]
/// addr-adl = nstring
///
/// Holds route from [RFC-2822] route-addr if non-NIL
fn addr_adl(input: &[u8]) -> IResult<&[u8], nstr> {
    nstring(input)
}

#[inline]
/// addr-mailbox = nstring
///
/// NIL indicates end of [RFC-2822] group;
/// if non-NIL and addr-host is NIL, holds [RFC-2822] group name.
/// Otherwise, holds [RFC-2822] local-part after removing [RFC-2822] quoting
fn addr_mailbox(input: &[u8]) -> IResult<&[u8], nstr> {
    nstring(input)
}

#[inline]
/// addr-host = nstring
///
/// NIL indicates [RFC-2822] group syntax.
/// Otherwise, holds [RFC-2822] domain name
fn addr_host(input: &[u8]) -> IResult<&[u8], nstr> {
    nstring(input)
}

#[cfg(test)]
mod test {
    use std::convert::{TryFrom, TryInto};

    use super::*;
    use crate::types::core::{IString, NString, NonZeroBytes};

    #[test]
    fn test_address() {
        let (rem, val) = address(b"(nil {3}\r\nxxx \"xxx\" nil)").unwrap();
        assert_eq!(
            val,
            Address::new(
                NString(None),
                NString(Some(IString::Literal(
                    NonZeroBytes::try_from(b"xxx".as_ref()).unwrap()
                ))),
                NString(Some(IString::Quoted("xxx".try_into().unwrap()))),
                NString(None),
            )
        );
        assert_eq!(rem, b"");
    }
}