69 lines
1.4 KiB
Rust
69 lines
1.4 KiB
Rust
|
use combine::{many1, parser::char::alpha_num, Parser, Stream};
|
||
|
|
||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||
|
pub struct Handle {
|
||
|
pub handle: String,
|
||
|
pub domain: String,
|
||
|
}
|
||
|
|
||
|
fn at<Input>() -> impl Parser<Input, Output = char>
|
||
|
where
|
||
|
Input: Stream<Token = char>,
|
||
|
{
|
||
|
combine::parser::char::char('@')
|
||
|
}
|
||
|
|
||
|
fn handle_part<Input>() -> impl Parser<Input, Output = String>
|
||
|
where
|
||
|
Input: Stream<Token = char>,
|
||
|
{
|
||
|
many1(alpha_num())
|
||
|
}
|
||
|
|
||
|
fn domain_part<Input>() -> impl Parser<Input, Output = String>
|
||
|
where
|
||
|
Input: Stream<Token = char>,
|
||
|
{
|
||
|
crate::url::domain().map(|d| d.0)
|
||
|
}
|
||
|
|
||
|
pub(crate) fn handle<Input>() -> impl Parser<Input, Output = Handle>
|
||
|
where
|
||
|
Input: Stream<Token = char>,
|
||
|
{
|
||
|
at().with(handle_part())
|
||
|
.skip(at())
|
||
|
.and(domain_part())
|
||
|
.map(|(handle, domain)| Handle { handle, domain })
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use super::*;
|
||
|
|
||
|
#[test]
|
||
|
fn parse_handle_part() {
|
||
|
let (_, rest) = handle_part().parse("as123").unwrap();
|
||
|
assert_eq!(rest, "");
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn parse_simple_handle() {
|
||
|
let (_, rest) = handle().parse("@asdf@asdf").unwrap();
|
||
|
assert_eq!(rest, "");
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn parse_complex_handle() {
|
||
|
let (_, rest) = handle()
|
||
|
.parse("@r2d2@telnet.towel.blinkenlights.nl")
|
||
|
.unwrap();
|
||
|
assert_eq!(rest, "");
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn dont_parse_invalid_handle() {
|
||
|
assert!(handle().parse("asdf@asdf").is_err())
|
||
|
}
|
||
|
}
|