mirror of https://github.com/rwf2/Rocket.git
Uniformly implement utility traits on URI types.
This commit is contained in:
parent
d2c2725689
commit
c2960e7e6f
|
@ -136,6 +136,22 @@ impl<B: 'static + ToOwned + ?Sized> IntoOwned for Cow<'_, B> {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_into_owned_self {
|
||||
($($T:ty),*) => ($(
|
||||
impl IntoOwned for $T {
|
||||
type Owned = Self;
|
||||
|
||||
#[inline(always)]
|
||||
fn into_owned(self) -> <Self as IntoOwned>::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
impl_into_owned_self!(u8, u16, u32, u64, usize);
|
||||
impl_into_owned_self!(i8, i16, i32, i64, isize);
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
// Outside of http, this is used by a test.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::borrow::Cow;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
use crate::parse::{Extent, IndexedStr};
|
||||
|
@ -97,20 +96,6 @@ pub struct Absolute<'a> {
|
|||
pub(crate) query: Option<Data<'a, fmt::Query>>,
|
||||
}
|
||||
|
||||
impl IntoOwned for Absolute<'_> {
|
||||
type Owned = Absolute<'static>;
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
Absolute {
|
||||
source: self.source.into_owned(),
|
||||
scheme: self.scheme.into_owned(),
|
||||
authority: self.authority.into_owned(),
|
||||
path: self.path.into_owned(),
|
||||
query: self.query.into_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Absolute<'a> {
|
||||
/// Parses the string `string` into an `Absolute`. Parsing will never
|
||||
/// allocate. Returns an `Error` if `string` is not a valid absolute URI.
|
||||
|
@ -480,30 +465,9 @@ impl<'a> Absolute<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a String> for Absolute<'a> {
|
||||
type Error = Error<'a>;
|
||||
impl_serde!(Absolute<'a>, "an absolute-form URI");
|
||||
|
||||
fn try_from(value: &'a String) -> Result<Self, Self::Error> {
|
||||
Absolute::parse(value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for Absolute<'a> {
|
||||
type Error = Error<'a>;
|
||||
|
||||
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
Absolute::parse(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> PartialEq<Absolute<'b>> for Absolute<'a> {
|
||||
fn eq(&self, other: &Absolute<'b>) -> bool {
|
||||
self.scheme() == other.scheme()
|
||||
&& self.authority() == other.authority()
|
||||
&& self.path() == other.path()
|
||||
&& self.query() == other.query()
|
||||
}
|
||||
}
|
||||
impl_traits!(Absolute, scheme, authority, path, query);
|
||||
|
||||
impl std::fmt::Display for Absolute<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -520,5 +484,3 @@ impl std::fmt::Display for Absolute<'_> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl_serde!(Absolute<'a>, "an absolute-form URI");
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::fmt::{self, Display};
|
||||
use std::convert::TryFrom;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
|
@ -52,19 +51,6 @@ pub struct Authority<'a> {
|
|||
port: Option<u16>,
|
||||
}
|
||||
|
||||
impl IntoOwned for Authority<'_> {
|
||||
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> {
|
||||
// SAFETY: `source` must be valid UTF-8.
|
||||
// CORRECTNESS: `host` must be non-empty.
|
||||
|
@ -225,13 +211,9 @@ impl<'a> Authority<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'b> PartialEq<Authority<'b>> for Authority<'_> {
|
||||
fn eq(&self, other: &Authority<'b>) -> bool {
|
||||
self.user_info() == other.user_info()
|
||||
&& self.host() == other.host()
|
||||
&& self.port() == other.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 {
|
||||
|
@ -247,22 +229,3 @@ impl Display for Authority<'_> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Because inference doesn't take `&String` to `&str`.
|
||||
impl<'a> TryFrom<&'a String> for Authority<'a> {
|
||||
type Error = Error<'a>;
|
||||
|
||||
fn try_from(value: &'a String) -> Result<Self, Self::Error> {
|
||||
Authority::parse(value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for Authority<'a> {
|
||||
type Error = Error<'a>;
|
||||
|
||||
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
Authority::parse(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl_serde!(Authority<'a>, "an authority-form URI");
|
||||
|
|
|
@ -1,49 +1,6 @@
|
|||
//! Types for URIs and traits for rendering URI components.
|
||||
|
||||
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_use]
|
||||
mod uri;
|
||||
mod origin;
|
||||
mod reference;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use std::borrow::Cow;
|
||||
use std::convert::TryFrom;
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
use crate::parse::{Extent, IndexedStr, uri::tables::is_pchar};
|
||||
|
@ -116,52 +114,6 @@ pub struct Origin<'a> {
|
|||
pub(crate) query: Option<Data<'a, fmt::Query>>,
|
||||
}
|
||||
|
||||
impl Hash for Origin<'_> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.path().hash(state);
|
||||
self.query().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> PartialEq<Origin<'b>> for Origin<'a> {
|
||||
fn eq(&self, other: &Origin<'b>) -> bool {
|
||||
self.path() == other.path() && self.query() == other.query()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Origin<'_> { }
|
||||
|
||||
impl PartialEq<str> for Origin<'_> {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
let (path, query) = RawStr::new(other).split_at_byte(b'?');
|
||||
self.path() == path && self.query().map_or("", |q| q.as_str()) == query
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for Origin<'_> {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self.eq(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Origin<'_>> for str {
|
||||
fn eq(&self, other: &Origin<'_>) -> bool {
|
||||
other.eq(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoOwned for Origin<'_> {
|
||||
type Owned = Origin<'static>;
|
||||
|
||||
fn into_owned(self) -> Origin<'static> {
|
||||
Origin {
|
||||
source: self.source.into_owned(),
|
||||
path: self.path.into_owned(),
|
||||
query: self.query.into_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Origin<'a> {
|
||||
/// The root: `'/'`.
|
||||
#[doc(hidden)]
|
||||
|
@ -474,30 +426,9 @@ impl<'a> Origin<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Origin<'static> {
|
||||
type Error = Error<'static>;
|
||||
impl_serde!(Origin<'a>, "an origin-form URI");
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
Origin::parse_owned(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Because inference doesn't take `&String` to `&str`.
|
||||
impl<'a> TryFrom<&'a String> for Origin<'a> {
|
||||
type Error = Error<'a>;
|
||||
|
||||
fn try_from(value: &'a String) -> Result<Self, Self::Error> {
|
||||
Origin::parse(value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for Origin<'a> {
|
||||
type Error = Error<'a>;
|
||||
|
||||
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
Origin::parse(value)
|
||||
}
|
||||
}
|
||||
impl_traits!(Origin, path, query);
|
||||
|
||||
impl std::fmt::Display for Origin<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -510,8 +441,6 @@ impl std::fmt::Display for Origin<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl_serde!(Origin<'a>, "an origin-form URI");
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Origin;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, convert::TryFrom};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::RawStr;
|
||||
use crate::ext::IntoOwned;
|
||||
|
@ -427,30 +427,9 @@ impl<'a> Reference<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Reference<'_>> for Reference<'_> {
|
||||
fn eq(&self, other: &Reference<'_>) -> bool {
|
||||
self.scheme() == other.scheme()
|
||||
&& self.authority() == other.authority()
|
||||
&& self.path() == other.path()
|
||||
&& self.query() == other.query()
|
||||
&& self.fragment() == other.fragment()
|
||||
}
|
||||
}
|
||||
impl_traits!(Reference, authority, scheme, path, query, fragment);
|
||||
|
||||
impl IntoOwned for Reference<'_> {
|
||||
type Owned = Reference<'static>;
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
Reference {
|
||||
source: self.source.into_owned(),
|
||||
scheme: self.scheme.into_owned(),
|
||||
authority: self.authority.into_owned(),
|
||||
path: self.path.into_owned(),
|
||||
query: self.query.into_owned(),
|
||||
fragment: self.fragment.into_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl_serde!(Reference<'a>, "a URI-reference");
|
||||
|
||||
impl<'a> From<Absolute<'a>> for Reference<'a> {
|
||||
fn from(absolute: Absolute<'a>) -> Self {
|
||||
|
@ -507,31 +486,6 @@ impl From<Asterisk> for Reference<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for Reference<'a> {
|
||||
type Error = Error<'a>;
|
||||
|
||||
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
Reference::parse(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Reference<'static> {
|
||||
type Error = Error<'static>;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
Reference::parse_owned(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Because inference doesn't take `&String` to `&str`.
|
||||
impl<'a> TryFrom<&'a String> for Reference<'a> {
|
||||
type Error = Error<'a>;
|
||||
|
||||
fn try_from(value: &'a String) -> Result<Self, Self::Error> {
|
||||
Reference::parse(value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Reference<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(scheme) = self.scheme() {
|
||||
|
@ -555,5 +509,3 @@ impl std::fmt::Display for Reference<'_> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl_serde!(Reference<'a>, "a URI-reference");
|
||||
|
|
|
@ -343,3 +343,121 @@ impl_uri_from!(Authority<'a>);
|
|||
impl_uri_from!(Absolute<'a>);
|
||||
impl_uri_from!(Reference<'a>);
|
||||
impl_uri_from!(Asterisk);
|
||||
|
||||
/// Implements Serialize and Deserialize for any 'URI' looking type.
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements PartialEq, Eq, Hash, TryFrom, and IntoOwned for a URI.
|
||||
macro_rules! impl_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)
|
||||
}
|
||||
}
|
||||
|
||||
// Because inference doesn't take `&String` to `&str`.
|
||||
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);)*
|
||||
}
|
||||
}
|
||||
|
||||
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()),*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue