use std::fmt::{self, Display};
use std::borrow::Cow;
use crate::ext::IntoOwned;
use crate::uri::{Origin, Authority, Absolute, Reference, Asterisk};
use crate::uri::error::{Error, TryFromUriError};
#[derive(Debug, PartialEq, Clone)]
pub enum Uri<'a> {
Asterisk(Asterisk),
Origin(Origin<'a>),
Authority(Authority<'a>),
Absolute(Absolute<'a>),
Reference(Reference<'a>),
}
impl<'a> Uri<'a> {
pub fn parse<T>(string: &'a str) -> Result<Uri<'a>, Error<'_>>
where T: Into<Uri<'a>> + TryFrom<&'a str, Error = Error<'a>>
{
T::try_from(string).map(|v| v.into())
}
pub fn parse_any(string: &'a str) -> Result<Uri<'a>, Error<'_>> {
crate::parse::uri::from_str(string)
}
pub fn origin(&self) -> Option<&Origin<'a>> {
match self {
Uri::Origin(ref inner) => Some(inner),
_ => None
}
}
pub fn authority(&self) -> Option<&Authority<'a>> {
match self {
Uri::Authority(ref inner) => Some(inner),
_ => None
}
}
pub fn absolute(&self) -> Option<&Absolute<'a>> {
match self {
Uri::Absolute(ref inner) => Some(inner),
_ => None
}
}
pub fn reference(&self) -> Option<&Reference<'a>> {
match self {
Uri::Reference(ref inner) => Some(inner),
_ => None
}
}
}
pub(crate) unsafe fn as_utf8_unchecked(input: Cow<'_, [u8]>) -> Cow<'_, str> {
match input {
Cow::Borrowed(bytes) => Cow::Borrowed(std::str::from_utf8_unchecked(bytes)),
Cow::Owned(bytes) => Cow::Owned(String::from_utf8_unchecked(bytes))
}
}
impl IntoOwned for Uri<'_> {
type Owned = Uri<'static>;
fn into_owned(self) -> Uri<'static> {
match self {
Uri::Origin(origin) => Uri::Origin(origin.into_owned()),
Uri::Authority(authority) => Uri::Authority(authority.into_owned()),
Uri::Absolute(absolute) => Uri::Absolute(absolute.into_owned()),
Uri::Reference(reference) => Uri::Reference(reference.into_owned()),
Uri::Asterisk(asterisk) => Uri::Asterisk(asterisk)
}
}
}
impl Display for Uri<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Uri::Origin(ref origin) => write!(f, "{}", origin),
Uri::Authority(ref authority) => write!(f, "{}", authority),
Uri::Absolute(ref absolute) => write!(f, "{}", absolute),
Uri::Reference(ref reference) => write!(f, "{}", reference),
Uri::Asterisk(ref asterisk) => write!(f, "{}", asterisk)
}
}
}
macro_rules! impl_uri_from {
($T:ident $(<$lt:lifetime>)?) => (
impl<'a> From<$T $(<$lt>)?> for Uri<'a> {
fn from(other: $T $(<$lt>)?) -> Uri<'a> {
Uri::$T(other)
}
}
impl<'a> TryFrom<Uri<'a>> for $T $(<$lt>)? {
type Error = TryFromUriError;
fn try_from(uri: Uri<'a>) -> Result<Self, Self::Error> {
match uri {
Uri::$T(inner) => Ok(inner),
_ => Err(TryFromUriError(()))
}
}
}
impl<'b, $($lt)?> PartialEq<$T $(<$lt>)?> for Uri<'b> {
fn eq(&self, other: &$T $(<$lt>)?) -> bool {
match self {
Uri::$T(inner) => inner == other,
_ => false
}
}
}
impl<'b, $($lt)?> PartialEq<Uri<'b>> for $T $(<$lt>)? {
fn eq(&self, other: &Uri<'b>) -> bool {
match other {
Uri::$T(inner) => inner == self,
_ => false
}
}
}
)
}
impl_uri_from!(Origin<'a>);
impl_uri_from!(Authority<'a>);
impl_uri_from!(Absolute<'a>);
impl_uri_from!(Reference<'a>);
impl_uri_from!(Asterisk);
macro_rules! impl_serde {
($T:ty, $expected:literal) => {
#[cfg(feature = "serde")]
mod serde {
use std::fmt;
use std::marker::PhantomData;
use super::*;
use serde_::ser::{Serialize, Serializer};
use serde_::de::{Deserialize, Deserializer, Error, Visitor};
impl<'a> Serialize for $T {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_string())
}
}
struct DeVisitor<'a>(PhantomData<&'a $T>);
impl<'de, 'a> Visitor<'de> for DeVisitor<'a> {
type Value = $T;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, $expected)
}
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
<$T>::parse_owned(v.to_string()).map_err(Error::custom)
}
fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
<$T>::parse_owned(v).map_err(Error::custom)
}
}
impl<'a, 'de> Deserialize<'de> for $T {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(DeVisitor(PhantomData))
}
}
}
};
}
macro_rules! impl_traits {
($T:ident, $($field:ident),* $(,)?) => {
impl_base_traits!($T, $($field),*);
impl crate::ext::IntoOwned for $T<'_> {
type Owned = $T<'static>;
fn into_owned(self) -> $T<'static> {
$T {
source: self.source.into_owned(),
$($field: self.$field.into_owned()),*
}
}
}
}
}
macro_rules! impl_base_traits {
($T:ident, $($field:ident),* $(,)?) => {
impl std::convert::TryFrom<String> for $T<'static> {
type Error = Error<'static>;
fn try_from(value: String) -> Result<Self, Self::Error> {
$T::parse_owned(value)
}
}
impl<'a> std::convert::TryFrom<&'a String> for $T<'a> {
type Error = Error<'a>;
fn try_from(value: &'a String) -> Result<Self, Self::Error> {
$T::parse(value.as_str())
}
}
impl<'a> std::convert::TryFrom<&'a str> for $T<'a> {
type Error = Error<'a>;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
$T::parse(value)
}
}
impl<'a, 'b> PartialEq<$T<'b>> for $T<'a> {
fn eq(&self, other: &$T<'b>) -> bool {
true $(&& self.$field() == other.$field())*
}
}
impl PartialEq<str> for $T<'_> {
fn eq(&self, string: &str) -> bool {
$T::parse(string).map_or(false, |v| &v == self)
}
}
impl PartialEq<&str> for $T<'_> {
fn eq(&self, other: &&str) -> bool {
self.eq(*other)
}
}
impl PartialEq<$T<'_>> for str {
fn eq(&self, other: &$T<'_>) -> bool {
other.eq(self)
}
}
impl Eq for $T<'_> { }
impl std::hash::Hash for $T<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
$(self.$field().hash(state);)*
}
}
}
}