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
use crate::is_whitespace;
use nom::{map, named, take_till1, types::CompleteStr};

#[derive(Debug, PartialEq)]
pub enum Owner {
    Email(String),
    Handle(String),
    Text(String),
}

impl Owner {
    fn handle<'a>(handle: CompleteStr<'a>) -> Self {
        Owner::Handle(handle.trim_start_matches("@").to_string())
    }

    fn email<'a>(email: CompleteStr<'a>) -> Self {
        Owner::Email(email.to_string())
    }

    fn text<'a>(text: CompleteStr<'a>) -> Self {
        Owner::Text(text.to_string())
    }
}

impl<'a> From<CompleteStr<'a>> for Owner {
    fn from(input: CompleteStr<'a>) -> Self {
        if input.starts_with("@") {
            return Owner::handle(input);
        }
        if input.contains("@") && !input.ends_with("@") {
            return Owner::email(input);
        }
        Owner::text(input)
    }
}

named!(pub(crate) owner<CompleteStr, Owner>, map!(
    take_till1!(is_whitespace), Owner::from)
);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn handle() {
        let (rem, parsed) = owner(CompleteStr("@handle")).unwrap();

        assert_eq!(parsed, Owner::Handle("handle".into()));
        assert!(rem.is_empty());
    }

    #[test]
    fn email() {
        let (rem, parsed) = owner(CompleteStr("name@domain")).unwrap();

        assert_eq!(parsed, Owner::Email("name@domain".into()));
        assert!(rem.is_empty());
    }

    #[test]
    fn text() {
        let (rem, parsed) = owner(CompleteStr("text")).unwrap();

        assert_eq!(parsed, Owner::Text("text".into()));
        assert!(rem.is_empty());
    }
}