use serde::{Deserialize, Serialize};
use std::fmt;
use crate::{
core::{parse_transport, Transport},
uri::{parse_domain, Domain},
};
use nom::{
IResult,
character::{is_alphabetic, is_alphanumeric},
error::ParseError,
bytes::complete::{ take_while, tag},
combinator::map,
branch::alt
};
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum UriParam {
Transport(Transport),
Branch(String),
Received(Domain),
RPort,
Other(String, Option<String>)
}
impl UriParam {
pub fn from_key<'a, E: ParseError<&'a [u8]>>(
key: &'a [u8],
value: &'a [u8],
) -> Result<UriParam, nom::Err<E>> {
match key {
b"transport" => Ok(UriParam::Transport(parse_transport::<E>(&value)?.1)),
b"branch" => Ok(UriParam::Branch(
String::from_utf8(value.to_vec()).expect("Utf-8 Error"),
)),
b"received" => {
Ok(UriParam::Received(parse_domain::<E>(&value)?.1))
},
_method => Ok(UriParam::Other(
String::from_utf8_lossy(key).to_string(),
Some(String::from_utf8_lossy(value).to_string())
)),
}
}
}
impl fmt::Display for UriParam {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UriParam::Transport(trans) => write!(f, ";transport={}", trans),
UriParam::Branch(branch) => write!(f, ";branch={}", branch),
UriParam::Received(branch) => write!(f, ";received={}", branch),
UriParam::RPort => write!(f, ";rport"),
UriParam::Other(key, Some(value)) => write!(f, ";{}={}", key, value),
UriParam::Other(key, None) => write!(f, ";{}", key)
}
}
}
pub fn parse_param<'a, E: ParseError<&'a [u8]>>(input: &'a [u8]) -> IResult<&'a [u8], UriParam, E> {
alt::<_, _, E, _>(
(
map(tag::<_, _, E>(";rport"), |_| UriParam::RPort),
parse_named_param,
parse_single_param
)
)(input)
}
pub fn parse_named_param<'a, E: ParseError<&'a [u8]>>(input: &'a [u8]) -> IResult<&'a [u8], UriParam, E> {
let (input, _) = tag(";")(input)?;
let (input, key) = take_while(is_alphabetic)(input)?;
let (input, _) = tag("=")(input)?;
let (input, value) = take_while(|item| is_alphanumeric(item) || b'.' == item)(input)?;
UriParam::from_key::<E>(key, value)
.and_then(|item| Ok((input, item)))
}
pub fn parse_single_param<'a, E: ParseError<&'a [u8]>>(input: &'a [u8]) -> IResult<&'a [u8], UriParam, E> {
let (input, _) = tag(";")(input)?;
let (input, key) = take_while(is_alphabetic)(input)?;
Ok((input, UriParam::Other(String::from_utf8_lossy(key).into(), None)))
}
pub fn parse_params<'a, E: ParseError<&'a [u8]>>(input: &'a [u8]) -> IResult<&'a [u8], Vec<UriParam>, E> {
let mut results = vec![];
let mut data = input;
while let Ok((remains, param)) = parse_param::<E>(&data) {
results.push(param);
data = remains;
}
Ok((data, results))
}