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::{error::NomResult, is_whitespace}; use nom::{bytes::complete::take_till1, combinator::map, error::context}; #[derive(Debug, Clone, PartialEq, Eq)] pub enum Owner { Email(String), Handle(String), Text(String), } impl Owner { fn handle<'a>(handle: &'a str) -> Self { Owner::Handle(handle.trim_start_matches('@').to_string()) } fn email<'a>(email: &'a str) -> Self { Owner::Email(email.to_string()) } fn text<'a>(text: &'a str) -> Self { Owner::Text(text.to_string()) } } impl<'a> From<&'a str> for Owner { fn from(input: &'a str) -> Self { if input.starts_with('@') { return Owner::handle(input); } if input.contains('@') && !input.ends_with('@') { return Owner::email(input); } Owner::text(input) } } pub(crate) fn owner(input: &str) -> NomResult<Owner> { context("owner", map(take_till1(is_whitespace), Owner::from))(input) } #[cfg(test)] mod tests { use super::*; #[test] fn handle() { let (rem, parsed) = owner("@handle").unwrap(); assert_eq!(parsed, Owner::Handle("handle".into())); assert!(rem.is_empty()); } #[test] fn email() { let (rem, parsed) = owner("name@domain").unwrap(); assert_eq!(parsed, Owner::Email("name@domain".into())); assert!(rem.is_empty()); } #[test] fn text() { let (rem, parsed) = owner("text").unwrap(); assert_eq!(parsed, Owner::Text("text".into())); assert!(rem.is_empty()); } }