diff --git a/core/http/src/parse/uri/mod.rs b/core/http/src/parse/uri/mod.rs index d8029e5f..d7e05288 100644 --- a/core/http/src/parse/uri/mod.rs +++ b/core/http/src/parse/uri/mod.rs @@ -4,7 +4,7 @@ pub(crate) mod tables; #[cfg(test)] mod tests; -use crate::uri::{Uri, Origin, Absolute, Authority, Reference}; +use crate::uri::{Uri, Origin, Absolute, Authority, Reference, Asterisk}; use self::parser::*; @@ -32,6 +32,11 @@ pub fn absolute_from_str(s: &str) -> Result, Error<'_>> { Ok(parse!(absolute: RawInput::new(s.as_bytes()))?) } +#[inline] +pub fn asterisk_from_str(s: &str) -> Result> { + Ok(parse!(asterisk: RawInput::new(s.as_bytes()))?) +} + #[inline] pub fn reference_from_str(s: &str) -> Result, Error<'_>> { Ok(parse!(reference: RawInput::new(s.as_bytes()))?) diff --git a/core/http/src/parse/uri/parser.rs b/core/http/src/parse/uri/parser.rs index 68b4712e..48e6d35f 100644 --- a/core/http/src/parse/uri/parser.rs +++ b/core/http/src/parse/uri/parser.rs @@ -35,7 +35,7 @@ pub fn uri<'a>(input: &mut RawInput<'a>) -> Result<'a, Uri<'a>> { // To resolve all ambiguities with preference, we might need to look at the // complete string twice: origin/ref, asterisk/ref, authority/absolute. switch! { - complete(|i| eat(i, b'*')) => Uri::Asterisk(Asterisk), + asterisk@complete(asterisk) => Uri::Asterisk(asterisk), origin@complete(origin) => Uri::Origin(origin), authority@complete(authority) => Uri::Authority(authority), absolute@complete(absolute) => Uri::Absolute(absolute), @@ -43,6 +43,12 @@ pub fn uri<'a>(input: &mut RawInput<'a>) -> Result<'a, Uri<'a>> { } } +#[parser] +pub fn asterisk<'a>(input: &mut RawInput<'a>) -> Result<'a, Asterisk> { + eat(b'*')?; + Asterisk +} + #[parser] pub fn origin<'a>(input: &mut RawInput<'a>) -> Result<'a, Origin<'a>> { let (_, path, query) = (peek(b'/')?, path()?, query()?); diff --git a/core/http/src/uri/absolute.rs b/core/http/src/uri/absolute.rs index 48544036..1bb0a617 100644 --- a/core/http/src/uri/absolute.rs +++ b/core/http/src/uri/absolute.rs @@ -65,19 +65,28 @@ use crate::uri::{Authority, Path, Query, Data, Error, as_utf8_unchecked, fmt}; /// # } /// ``` /// -/// ## Serde +/// # (De)serialization /// -/// For convience, `Absolute` implements `Serialize` and `Deserialize`. -/// Because `Absolute` has a lifetime parameter, serde requires a borrow -/// attribute for the derive macro to work. If you want to own the Uri, -/// rather than borrow from the deserializer, use `'static`. +/// `Absolute` is both `Serialize` and `Deserialize`: /// -/// ```ignore -/// #[derive(Deserialize)] -/// struct Uris<'a> { -/// #[serde(borrow)] -/// absolute: Absolute<'a>, +/// ```rust +/// # #[cfg(feature = "serde")] mod serde { +/// # use _serde as serde; +/// use serde::{Serialize, Deserialize}; +/// use rocket::http::uri::Absolute; +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriOwned { +/// uri: Absolute<'static>, /// } +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriBorrowed<'a> { +/// uri: Absolute<'a>, +/// } +/// # } /// ``` #[derive(Debug, Clone)] pub struct Absolute<'a> { @@ -130,14 +139,12 @@ impl<'a> Absolute<'a> { crate::parse::uri::absolute_from_str(string) } - /// Parses the string `string` into an `Absolute`. Parsing will never - /// May allocate on error. + /// Parses the string `string` into an `Absolute`. Allocates minimally on + /// success and error. /// - /// TODO: avoid allocation - /// - /// This method should be used instead of [`Absolute::parse()`] when - /// the source URI is already a `String`. Returns an `Error` if `string` is - /// not a valid absolute URI. + /// This method should be used instead of [`Absolute::parse()`] when the + /// source URI is already a `String`. Returns an `Error` if `string` is not + /// a valid absolute URI. /// /// # Example /// @@ -151,9 +158,10 @@ impl<'a> Absolute<'a> { /// assert_eq!(uri.path(), "/foo/2/three"); /// assert!(uri.query().is_none()); /// ``` + // TODO: Avoid all allocations. pub fn parse_owned(string: String) -> Result, Error<'static>> { let absolute = Absolute::parse(&string).map_err(|e| e.into_owned())?; - debug_assert!(absolute.source.is_some(), "Origin source parsed w/o source"); + debug_assert!(absolute.source.is_some(), "Absolute parsed w/o source"); let absolute = Absolute { scheme: absolute.scheme.into_owned(), @@ -513,43 +521,4 @@ impl std::fmt::Display for Absolute<'_> { } } -#[cfg(feature = "serde")] -mod serde { - use std::fmt; - - use super::Absolute; - use _serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer, Error, Visitor}}; - - impl<'a> Serialize for Absolute<'a> { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.to_string()) - } - } - - struct AbsoluteVistor; - - impl<'a> Visitor<'a> for AbsoluteVistor { - type Value = Absolute<'a>; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "absolute Uri") - } - - fn visit_str(self, v: &str) -> Result { - Absolute::parse_owned(v.to_string()).map_err(Error::custom) - } - - fn visit_string(self, v: String) -> Result { - Absolute::parse_owned(v).map_err(Error::custom) - } - - fn visit_borrowed_str(self, v: &'a str) -> Result { - Absolute::parse(v).map_err(Error::custom) - } - } - - impl<'a, 'de: 'a> Deserialize<'de> for Absolute<'a> { - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_str(AbsoluteVistor) - } - } -} +impl_serde!(Absolute<'a>, "an absolute-form URI"); diff --git a/core/http/src/uri/asterisk.rs b/core/http/src/uri/asterisk.rs index 96095bfb..53f7b780 100644 --- a/core/http/src/uri/asterisk.rs +++ b/core/http/src/uri/asterisk.rs @@ -1,54 +1,70 @@ +use crate::ext::IntoOwned; +use crate::uri::Error; + /// The literal `*` URI. /// -/// ## Serde +/// # (De)serialization /// -/// For convience, `Asterisk` implements `Serialize` and `Deserialize`. +/// `Asterisk` is both `Serialize` and `Deserialize`: +/// +/// ```rust +/// # #[cfg(feature = "serde")] mod serde { +/// # use _serde as serde; +/// use serde::{Serialize, Deserialize}; +/// use rocket::http::uri::Asterisk; +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriOwned { +/// uri: Asterisk, +/// } +/// # } +/// ``` #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub struct Asterisk; +impl Asterisk { + /// Parses the string `string` into an `Asterisk`. Parsing will never + /// allocate. Returns an `Error` if `string` is not a valid asterisk URI. + /// + /// # Example + /// + /// ```rust + /// # #[macro_use] extern crate rocket; + /// use rocket::http::uri::Asterisk; + /// + /// assert!(Asterisk::parse("*").is_ok()); + /// assert!(Asterisk::parse("/foo/bar").is_err()); + /// + /// // Prefer to use `uri!()` when the input is statically known: + /// let uri = uri!("*"); + /// assert_eq!(uri, Asterisk); + /// ``` + pub fn parse(string: &str) -> Result> { + crate::parse::uri::asterisk_from_str(string) + } + + /// Parses the string `string` into an `Asterisk`. This is equivalent to + /// [`Asterisk::parse()`]. + /// + /// # Example + /// + /// ```rust + /// # #[macro_use] extern crate rocket; + /// use rocket::http::uri::Asterisk; + /// + /// assert!(Asterisk::parse_owned("*".to_string()).is_ok()); + /// assert!(Asterisk::parse_owned("/foo/bar".to_string()).is_err()); + /// ``` + pub fn parse_owned(string: String) -> Result> { + Asterisk::parse(&string).map_err(|e| e.into_owned()) + } +} + impl std::fmt::Display for Asterisk { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { "*".fmt(f) } } -#[cfg(feature = "serde")] -mod serde { - use std::fmt; - - use super::Asterisk; - use _serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer, Error, Visitor}}; - - impl Serialize for Asterisk { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str("*") - } - } - - struct AsteriskVistor; - - impl<'a> Visitor<'a> for AsteriskVistor { - type Value = Asterisk; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "asterisk Uri") - } - - // This method should be the only one that needs to be implemented, since the - // other two methods (`visit_string` & `visit_borrowed_str`) have default implementations - // that just call this one. We don't benefit from taking ownership or borrowing from the - // deserializer, so this should be perfect. - fn visit_str(self, v: &str) -> Result { - if v == "*" { - Ok(Asterisk) - }else { - Err(E::custom(format!("`{}` is not a valid asterisk uri", v))) - } - } - } - - impl<'de> Deserialize<'de> for Asterisk { - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_str(AsteriskVistor) - } - } -} +impl_serde!(Asterisk, "an asterisk-form URI, '*'"); diff --git a/core/http/src/uri/authority.rs b/core/http/src/uri/authority.rs index b06a7fd6..ad070449 100644 --- a/core/http/src/uri/authority.rs +++ b/core/http/src/uri/authority.rs @@ -21,19 +21,28 @@ use crate::uri::{as_utf8_unchecked, error::Error}; /// /// Only the host part of the URI is required. /// -/// ## Serde +/// # (De)serialization /// -/// For convience, `Authority` implements `Serialize` and `Deserialize`. -/// Because `Authority` has a lifetime parameter, serde requires a borrow -/// attribute for the derive macro to work. If you want to own the Uri, -/// rather than borrow from the deserializer, use `'static`. +/// `Authority` is both `Serialize` and `Deserialize`: /// -/// ```ignore -/// #[derive(Deserialize)] -/// struct Uris<'a> { -/// #[serde(borrow)] -/// authority: Authority<'a>, +/// ```rust +/// # #[cfg(feature = "serde")] mod serde { +/// # use _serde as serde; +/// use serde::{Serialize, Deserialize}; +/// use rocket::http::uri::Authority; +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriOwned { +/// uri: Authority<'static>, /// } +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriBorrowed<'a> { +/// uri: Authority<'a>, +/// } +/// # } /// ``` #[derive(Debug, Clone)] pub struct Authority<'a> { @@ -124,8 +133,8 @@ impl<'a> Authority<'a> { crate::parse::uri::authority_from_str(string) } - /// Parses the string `string` into an `Authority`. Parsing will never allocate. - /// May allocate on error. + /// Parses the string `string` into an `Authority`. Parsing never allocates + /// on success. May allocate on error. /// /// This method should be used instead of [`Authority::parse()`] when /// the source URI is already a `String`. Returns an `Error` if `string` is @@ -145,7 +154,7 @@ impl<'a> Authority<'a> { /// ``` pub fn parse_owned(string: String) -> Result, Error<'static>> { let authority = Authority::parse(&string).map_err(|e| e.into_owned())?; - debug_assert!(authority.source.is_some(), "Origin source parsed w/o source"); + debug_assert!(authority.source.is_some(), "Authority parsed w/o source"); let authority = Authority { host: authority.host.into_owned(), @@ -256,43 +265,4 @@ impl<'a> TryFrom<&'a str> for Authority<'a> { } } -#[cfg(feature = "serde")] -mod serde { - use std::fmt; - - use super::Authority; - use _serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer, Error, Visitor}}; - - impl<'a> Serialize for Authority<'a> { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.to_string()) - } - } - - struct AuthorityVistor; - - impl<'a> Visitor<'a> for AuthorityVistor { - type Value = Authority<'a>; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "authority Uri") - } - - fn visit_str(self, v: &str) -> Result { - Authority::parse_owned(v.to_string()).map_err(Error::custom) - } - - fn visit_string(self, v: String) -> Result { - Authority::parse_owned(v).map_err(Error::custom) - } - - fn visit_borrowed_str(self, v: &'a str) -> Result { - Authority::parse(v).map_err(Error::custom) - } - } - - impl<'a, 'de: 'a> Deserialize<'de> for Authority<'a> { - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_str(AuthorityVistor) - } - } -} +impl_serde!(Authority<'a>, "an authority-form URI"); diff --git a/core/http/src/uri/mod.rs b/core/http/src/uri/mod.rs index 9211412f..94d6cba7 100644 --- a/core/http/src/uri/mod.rs +++ b/core/http/src/uri/mod.rs @@ -1,5 +1,49 @@ //! 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(&self, serializer: S) -> Result { + 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(self, v: &str) -> Result { + <$T>::parse_owned(v.to_string()).map_err(Error::custom) + } + + fn visit_string(self, v: String) -> Result { + <$T>::parse_owned(v).map_err(Error::custom) + } + } + + impl<'a, 'de> Deserialize<'de> for $T { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_str(DeVisitor(PhantomData)) + } + } + } + }; +} + mod uri; mod origin; mod reference; diff --git a/core/http/src/uri/origin.rs b/core/http/src/uri/origin.rs index a76ffe57..466045d5 100644 --- a/core/http/src/uri/origin.rs +++ b/core/http/src/uri/origin.rs @@ -86,19 +86,28 @@ use crate::{RawStr, RawStrBuf}; /// # } /// ``` /// -/// ## Serde +/// # (De)serialization /// -/// For convience, `Origin` implements `Serialize` and `Deserialize`. -/// Because `Origin` has a lifetime parameter, serde requires a borrow -/// attribute for the derive macro to work. If you want to own the Uri, -/// rather than borrow from the deserializer, use `'static`. +/// `Origin` is both `Serialize` and `Deserialize`: /// -/// ```ignore -/// #[derive(Deserialize)] -/// struct Uris<'a> { -/// #[serde(borrow)] -/// origin: Origin<'a>, +/// ```rust +/// # #[cfg(feature = "serde")] mod serde { +/// # use _serde as serde; +/// use serde::{Serialize, Deserialize}; +/// use rocket::http::uri::Origin; +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriOwned { +/// uri: Origin<'static>, /// } +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriBorrowed<'a> { +/// uri: Origin<'a>, +/// } +/// # } /// ``` #[derive(Debug, Clone)] pub struct Origin<'a> { @@ -283,7 +292,7 @@ impl<'a> Origin<'a> { /// ``` pub fn parse_owned(string: String) -> Result, Error<'static>> { let origin = Origin::parse(&string).map_err(|e| e.into_owned())?; - debug_assert!(origin.source.is_some(), "Origin source parsed w/o source"); + debug_assert!(origin.source.is_some(), "Origin parsed w/o source"); Ok(Origin { path: origin.path.into_owned(), @@ -501,46 +510,7 @@ impl std::fmt::Display for Origin<'_> { } } -#[cfg(feature = "serde")] -mod serde { - use std::fmt; - - use super::Origin; - use _serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer, Error, Visitor}}; - - impl<'a> Serialize for Origin<'a> { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.to_string()) - } - } - - struct OriginVistor; - - impl<'a> Visitor<'a> for OriginVistor { - type Value = Origin<'a>; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "origin Uri") - } - - fn visit_str(self, v: &str) -> Result { - Origin::parse_owned(v.to_string()).map_err(E::custom) - } - - fn visit_string(self, v: String) -> Result { - Origin::parse_owned(v).map_err(E::custom) - } - - fn visit_borrowed_str(self, v: &'a str) -> Result { - Origin::parse(v).map_err(E::custom) - } - } - - impl<'a, 'de: 'a> Deserialize<'de> for Origin<'a> { - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_str(OriginVistor) - } - } -} +impl_serde!(Origin<'a>, "an origin-form URI"); #[cfg(test)] mod tests { diff --git a/core/http/src/uri/reference.rs b/core/http/src/uri/reference.rs index 204b6d31..b50f3a7a 100644 --- a/core/http/src/uri/reference.rs +++ b/core/http/src/uri/reference.rs @@ -46,19 +46,28 @@ use crate::parse::{Extent, IndexedStr}; /// `Reference` when possible, as is demonstrated above for `absolute` and /// `origin`. /// -/// ## Serde +/// # (De)serialization /// -/// For convience, `Reference` implements `Serialize` and `Deserialize`. -/// Because `Reference` has a lifetime parameter, serde requires a borrow -/// attribute for the derive macro to work. If you want to own the Uri, -/// rather than borrow from the deserializer, use `'static`. +/// `Reference` is both `Serialize` and `Deserialize`: /// -/// ```ignore -/// #[derive(Deserialize)] -/// struct Uris<'a> { -/// #[serde(borrow)] -/// reference: Reference<'a>, +/// ```rust +/// # #[cfg(feature = "serde")] mod serde { +/// # use _serde as serde; +/// use serde::{Serialize, Deserialize}; +/// use rocket::http::uri::Reference; +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriOwned { +/// uri: Reference<'static>, /// } +/// +/// #[derive(Deserialize, Serialize)] +/// # #[serde(crate = "_serde")] +/// struct UriBorrowed<'a> { +/// uri: Reference<'a>, +/// } +/// # } /// ``` #[derive(Debug, Clone)] pub struct Reference<'a> { @@ -159,14 +168,12 @@ impl<'a> Reference<'a> { /// assert_eq!(uri.query().unwrap(), "query"); /// assert_eq!(uri.fragment().unwrap(), "fragment"); /// ``` - pub fn parse(string: &'a str) -> Result> { + pub fn parse(string: &'a str) -> Result, Error<'a>> { crate::parse::uri::reference_from_str(string) } - /// Parses the string `string` into a `Reference`. Never allocates on - /// success. May allocate on error. - /// - /// TODO: Avoid allocation + /// Parses the string `string` into a `Reference`. Allocates minimally on + /// success and error. /// /// This method should be used instead of [`Reference::parse()`] when the /// source URI is already a `String`. Returns an `Error` if `string` is not @@ -184,9 +191,10 @@ impl<'a> Reference<'a> { /// assert_eq!(uri.query().unwrap(), "2"); /// assert_eq!(uri.fragment().unwrap(), "3"); /// ``` - pub fn parse_owned(string: String) -> Result> { + // TODO: Avoid all allocations. + pub fn parse_owned(string: String) -> Result, Error<'static>> { let uri_ref = Reference::parse(&string).map_err(|e| e.into_owned())?; - debug_assert!(uri_ref.source.is_some(), "UriRef parsed w/o source"); + debug_assert!(uri_ref.source.is_some(), "Reference parsed w/o source"); Ok(Reference { scheme: uri_ref.scheme.into_owned(), @@ -548,43 +556,4 @@ impl std::fmt::Display for Reference<'_> { } } -#[cfg(feature = "serde")] -mod serde { - use std::fmt; - - use super::Reference; - use _serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer, Error, Visitor}}; - - impl<'a> Serialize for Reference<'a> { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.to_string()) - } - } - - struct ReferenceVistor; - - impl<'a> Visitor<'a> for ReferenceVistor { - type Value = Reference<'a>; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "reference Uri") - } - - fn visit_str(self, v: &str) -> Result { - Reference::parse_owned(v.to_string()).map_err(Error::custom) - } - - fn visit_string(self, v: String) -> Result { - Reference::parse_owned(v).map_err(Error::custom) - } - - fn visit_borrowed_str(self, v: &'a str) -> Result { - Reference::parse(v).map_err(Error::custom) - } - } - - impl<'a, 'de: 'a> Deserialize<'de> for Reference<'a> { - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_str(ReferenceVistor) - } - } -} +impl_serde!(Reference<'a>, "a URI-reference"); diff --git a/core/http/src/uri/uri.rs b/core/http/src/uri/uri.rs index f7aba737..aeccf37f 100644 --- a/core/http/src/uri/uri.rs +++ b/core/http/src/uri/uri.rs @@ -33,11 +33,6 @@ use crate::uri::error::{Error, TryFromUriError}; /// methods of the internal structure. /// /// [RFC 7230]: https://tools.ietf.org/html/rfc7230 -/// -/// ## Serde -/// Parsing a string into a `Uri` is ambgious, so `Uri` does not implement `Serialize` -/// or `Deserialize`, although all of the variants do. See [`Uri::parse_any`] for more -/// information #[derive(Debug, PartialEq, Clone)] pub enum Uri<'a> { /// An asterisk: exactly `*`. diff --git a/core/lib/tests/http_uri_serde.rs b/core/lib/tests/http_uri_serde.rs index 0093a246..35e22405 100644 --- a/core/lib/tests/http_uri_serde.rs +++ b/core/lib/tests/http_uri_serde.rs @@ -1,32 +1,25 @@ -use figment::{Figment, providers::Serialized}; -use rocket::{Config, uri}; -use rocket_http::uri::{Absolute, Asterisk, Authority, Origin, Reference}; use serde::{Serialize, Deserialize}; +use figment::{Figment, providers::Serialized}; use pretty_assertions::assert_eq; +use rocket::{Config, uri}; +use rocket::http::uri::{Absolute, Asterisk, Authority, Origin, Reference}; + #[derive(PartialEq, Debug, Serialize, Deserialize)] struct UriContainer<'a> { asterisk: Asterisk, - #[serde(borrow)] origin: Origin<'a>, - #[serde(borrow)] authority: Authority<'a>, - #[serde(borrow)] absolute: Absolute<'a>, - #[serde(borrow)] reference: Reference<'a>, } #[derive(PartialEq, Debug, Serialize, Deserialize)] struct UriContainerOwned { asterisk: Asterisk, - #[serde(borrow)] origin: Origin<'static>, - #[serde(borrow)] authority: Authority<'static>, - #[serde(borrow)] absolute: Absolute<'static>, - #[serde(borrow)] reference: Reference<'static>, } @@ -51,22 +44,6 @@ fn uri_serde() { reference: uri!("https://rocket.rs:8000/index.html").into(), }); - Ok(()) - }); -} - -#[test] -fn uri_serde_owned() { - figment::Jail::expect_with(|jail| { - jail.create_file("Rocket.toml", r#" - [default] - asterisk = "*" - origin = "/foo/bar?baz" - authority = "user:pass@rocket.rs:80" - absolute = "https://rocket.rs/foo/bar" - reference = "https://rocket.rs:8000/index.html" - "#)?; - let uris: UriContainerOwned = Config::figment().extract()?; assert_eq!(uris, UriContainerOwned { asterisk: Asterisk, @@ -90,7 +67,7 @@ fn uri_serde_round_trip() { reference: uri!("https://rocket.rs:8000/index.html").into(), })); - let uris: UriContainer<'_> = tmp.extract().expect("Parsing failed"); + let uris: UriContainer<'_> = tmp.extract().unwrap(); assert_eq!(uris, UriContainer { asterisk: Asterisk, origin: uri!("/foo/bar?baz"), @@ -98,4 +75,39 @@ fn uri_serde_round_trip() { absolute: uri!("https://rocket.rs/foo/bar"), reference: uri!("https://rocket.rs:8000/index.html").into(), }); + + let uris: UriContainerOwned = tmp.extract().unwrap(); + assert_eq!(uris, UriContainerOwned { + asterisk: Asterisk, + origin: uri!("/foo/bar?baz"), + authority: uri!("user:pass@rocket.rs:80"), + absolute: uri!("https://rocket.rs/foo/bar"), + reference: uri!("https://rocket.rs:8000/index.html").into(), + }); + + let tmp = Figment::from(Serialized::defaults(UriContainerOwned { + asterisk: Asterisk, + origin: uri!("/foo/bar?baz"), + authority: uri!("user:pass@rocket.rs:80"), + absolute: uri!("https://rocket.rs/foo/bar"), + reference: uri!("https://rocket.rs:8000/index.html").into(), + })); + + let uris: UriContainer<'_> = tmp.extract().unwrap(); + assert_eq!(uris, UriContainer { + asterisk: Asterisk, + origin: uri!("/foo/bar?baz"), + authority: uri!("user:pass@rocket.rs:80"), + absolute: uri!("https://rocket.rs/foo/bar"), + reference: uri!("https://rocket.rs:8000/index.html").into(), + }); + + let uris: UriContainerOwned = tmp.extract().unwrap(); + assert_eq!(uris, UriContainerOwned { + asterisk: Asterisk, + origin: uri!("/foo/bar?baz"), + authority: uri!("user:pass@rocket.rs:80"), + absolute: uri!("https://rocket.rs/foo/bar"), + reference: uri!("https://rocket.rs:8000/index.html").into(), + }); }