use std::fmt::{self, Display};
use std::borrow::Cow;
use crate::ext::IntoOwned;
use crate::parse::{Extent, IndexedStr};
use crate::uri::{as_utf8_unchecked, error::Error};
#[derive(Debug, Clone)]
pub struct Authority<'a> {
pub(crate) source: Option<Cow<'a, str>>,
pub(crate) user_info: Option<IndexedStr<'a>>,
host: IndexedStr<'a>,
port: Option<u16>,
}
impl<'a> Authority<'a> {
pub(crate) unsafe fn raw(
source: Cow<'a, [u8]>,
user_info: Option<Extent<&'a [u8]>>,
host: Extent<&'a [u8]>,
port: Option<u16>
) -> Authority<'a> {
Authority {
source: Some(as_utf8_unchecked(source)),
user_info: user_info.map(IndexedStr::from),
host: IndexedStr::from(host),
port,
}
}
#[doc(hidden)]
pub fn new(
user_info: impl Into<Option<&'a str>>,
host: &'a str,
port: impl Into<Option<u16>>,
) -> Self {
Authority::const_new(user_info.into(), host, port.into())
}
#[doc(hidden)]
pub const fn const_new(user_info: Option<&'a str>, host: &'a str, port: Option<u16>) -> Self {
Authority {
source: None,
user_info: match user_info {
Some(info) => Some(IndexedStr::Concrete(Cow::Borrowed(info))),
None => None
},
host: IndexedStr::Concrete(Cow::Borrowed(host)),
port,
}
}
pub fn parse(string: &'a str) -> Result<Authority<'a>, Error<'a>> {
crate::parse::uri::authority_from_str(string)
}
pub fn parse_owned(string: String) -> Result<Authority<'static>, Error<'static>> {
let authority = Authority::parse(&string).map_err(|e| e.into_owned())?;
debug_assert!(authority.source.is_some(), "Authority parsed w/o source");
let authority = Authority {
host: authority.host.into_owned(),
user_info: authority.user_info.into_owned(),
port: authority.port,
source: Some(Cow::Owned(string)),
};
Ok(authority)
}
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.from_cow_source(&self.source)
}
#[inline(always)]
pub fn port(&self) -> Option<u16> {
self.port
}
}
impl_serde!(Authority<'a>, "an authority-form URI");
impl_traits!(Authority, user_info, host, port);
impl Display for Authority<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(user_info) = self.user_info() {
write!(f, "{}@", user_info)?;
}
self.host().fmt(f)?;
if let Some(port) = self.port {
write!(f, ":{}", port)?;
}
Ok(())
}
}