use std::fmt::{self, Display};
use std::borrow::Cow;
use ext::IntoOwned;
use parse::{Indexed, IndexedStr};
use uri::{as_utf8_unchecked, Error};
#[derive(Debug, Clone)]
pub struct Authority<'a> {
source: Option<Cow<'a, str>>,
user_info: Option<IndexedStr<'a>>,
host: Host<IndexedStr<'a>>,
port: Option<u16>,
}
#[derive(Debug, Clone)]
pub(crate) enum Host<T> {
Bracketed(T),
Raw(T)
}
impl<T: IntoOwned> IntoOwned for Host<T> {
type Owned = Host<T::Owned>;
fn into_owned(self) -> Self::Owned {
self.map_inner(IntoOwned::into_owned)
}
}
impl<'a> IntoOwned for Authority<'a> {
type Owned = Authority<'static>;
fn into_owned(self) -> Authority<'static> {
Authority {
source: self.source.into_owned(),
user_info: self.user_info.into_owned(),
host: self.host.into_owned(),
port: self.port
}
}
}
impl<'a> Authority<'a> {
pub(crate) unsafe fn raw(
source: Cow<'a, [u8]>,
user_info: Option<Indexed<'a, [u8]>>,
host: Host<Indexed<'a, [u8]>>,
port: Option<u16>
) -> Authority<'a> {
Authority {
source: Some(as_utf8_unchecked(source)),
user_info: user_info.map(|u| u.coerce()),
host: host.map_inner(|inner| inner.coerce()),
port: port
}
}
#[cfg(test)]
pub(crate) fn new(
user_info: Option<&'a str>,
host: Host<&'a str>,
port: Option<u16>
) -> Authority<'a> {
Authority {
source: None,
user_info: user_info.map(|u| u.into()),
host: host.map_inner(|inner| inner.into()),
port: port
}
}
pub fn parse(string: &'a str) -> Result<Authority<'a>, Error<'a>> {
::parse::uri::authority_from_str(string)
}
pub fn user_info(&self) -> Option<&str> {
self.user_info.as_ref().map(|u| u.from_cow_source(&self.source))
}
#[inline(always)]
pub fn host(&self) -> &str {
self.host.inner().from_cow_source(&self.source)
}
#[inline(always)]
pub fn port(&self) -> Option<u16> {
self.port
}
}
impl<'a, 'b> PartialEq<Authority<'b>> for Authority<'a> {
fn eq(&self, other: &Authority<'b>) -> bool {
self.user_info() == other.user_info()
&& self.host() == other.host()
&& self.host.is_bracketed() == other.host.is_bracketed()
&& self.port() == other.port()
}
}
impl<'a> Display for Authority<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(user_info) = self.user_info() {
write!(f, "{}@", user_info)?;
}
match self.host {
Host::Bracketed(_) => write!(f, "[{}]", self.host())?,
Host::Raw(_) => write!(f, "{}", self.host())?
}
if let Some(port) = self.port {
write!(f, ":{}", port)?;
}
Ok(())
}
}
impl<T> Host<T> {
#[inline]
fn inner(&self) -> &T {
match *self {
Host::Bracketed(ref inner) | Host::Raw(ref inner) => inner
}
}
#[inline]
fn is_bracketed(&self) -> bool {
match *self {
Host::Bracketed(_) => true,
_ => false
}
}
#[inline]
fn map_inner<F, U>(self, f: F) -> Host<U>
where F: FnOnce(T) -> U
{
match self {
Host::Bracketed(inner) => Host::Bracketed(f(inner)),
Host::Raw(inner) => Host::Raw(f(inner))
}
}
}