rocket_http/uri/fmt/
uri_display.rs

1use std::collections::{BTreeMap, HashMap};
2use std::{fmt, path};
3use std::borrow::Cow;
4
5use time::{macros::format_description, format_description::FormatItem};
6
7use crate::RawStr;
8use crate::uri::fmt::{Part, Path, Query, Formatter};
9
10/// Trait implemented by types that can be displayed as part of a URI in
11/// [`uri!`].
12///
13/// Types implementing this trait can be displayed in a URI-safe manner. Unlike
14/// `Display`, the string written by a `UriDisplay` implementation must be
15/// URI-safe. In practice, this means that the string must either be
16/// percent-encoded or consist only of characters that are alphanumeric, "-",
17/// ".", "_", or "~" - the "unreserved" characters.
18///
19/// # Marker Generic: `Path`, `Query`
20///
21/// The [`Part`] parameter `P` in `UriDisplay<P>` must be either [`Path`] or
22/// [`Query`] (see the [`Part`] documentation for how this is enforced),
23/// resulting in either `UriDisplay<Path>` or `UriDisplay<Query>`.
24///
25/// As the names might imply, the `Path` version of the trait is used when
26/// displaying parameters in the path part of the URI while the `Query` version
27/// is used when displaying parameters in the query part of the URI. These
28/// distinct versions of the trait exist exactly to differentiate, at the
29/// type-level, where in the URI a value is to be written to, allowing for type
30/// safety in the face of differences between the two locations. For example,
31/// while it is valid to use a value of `None` in the query part, omitting the
32/// parameter entirely, doing so is _not_ valid in the path part. By
33/// differentiating in the type system, both of these conditions can be enforced
34/// appropriately through distinct implementations of `UriDisplay<Path>` and
35/// `UriDisplay<Query>`.
36///
37/// Occasionally, the implementation of `UriDisplay` is independent of where the
38/// parameter is to be displayed. When this is the case, the parameter may be
39/// kept generic. That is, implementations can take the form:
40///
41/// ```rust
42/// # extern crate rocket;
43/// # use std::fmt;
44/// # use rocket::http::uri::fmt::{Part, UriDisplay, Formatter};
45/// # struct SomeType;
46/// impl<P: Part> UriDisplay<P> for SomeType
47/// # { fn fmt(&self, f: &mut Formatter<P>) -> fmt::Result { Ok(()) } }
48/// ```
49///
50/// # Code Generation
51///
52/// When the [`uri!`] macro is used to generate a URI for a route, the types for
53/// the route's _path_ URI parameters must implement `UriDisplay<Path>`, while
54/// types in the route's query parameters must implement `UriDisplay<Query>`.
55/// Any parameters ignored with `_` must be of a type that implements
56/// [`Ignorable`]. The `UriDisplay` implementation for these types is used when
57/// generating the URI.
58///
59/// To illustrate `UriDisplay`'s role in code generation for `uri!`, consider
60/// the following route:
61///
62/// ```rust
63/// # #[macro_use] extern crate rocket;
64/// #[get("/item/<id>?<track>")]
65/// fn get_item(id: i32, track: Option<String>) { /* .. */ }
66/// ```
67///
68/// A URI for this route can be generated as follows:
69///
70/// ```rust
71/// # #[macro_use] extern crate rocket;
72/// # type T = ();
73/// # #[get("/item/<id>?<track>")]
74/// # fn get_item(id: i32, track: Option<String>) { /* .. */ }
75/// #
76/// // With unnamed parameters.
77/// uri!(get_item(100, Some("inbound")));
78///
79/// // With named parameters.
80/// uri!(get_item(id = 100, track = Some("inbound")));
81/// uri!(get_item(track = Some("inbound"), id = 100));
82///
83/// // Ignoring `track`.
84/// uri!(get_item(100, _));
85/// uri!(get_item(100, None as Option<String>));
86/// uri!(get_item(id = 100, track = _));
87/// uri!(get_item(track = _, id = 100));
88/// uri!(get_item(id = 100, track = None as Option<&str>));
89/// ```
90///
91/// After verifying parameters and their types, Rocket will generate code
92/// similar (in spirit) to the following:
93///
94/// ```rust
95/// # extern crate rocket;
96/// # use rocket::http::uri::Origin;
97/// # use rocket::http::uri::fmt::{UriDisplay, Path, Query};
98/// #
99/// Origin::parse(&format!("/item/{}?track={}",
100///     &100 as &dyn UriDisplay<Path>, &"inbound" as &dyn UriDisplay<Query>));
101/// ```
102///
103/// For this expression to typecheck, `i32` must implement `UriDisplay<Path>`
104/// and `&str` must implement `UriDisplay<Query>`. What's more, when `track` is
105/// ignored, `Option<String>` is required to implement [`Ignorable`]. As can be
106/// seen, the implementations will be used to display the value in a URI-safe
107/// manner.
108///
109/// [`uri!`]: ../../../../rocket/macro.uri.html
110///
111/// # Provided Implementations
112///
113/// Rocket implements `UriDisplay<P>` for all `P: Part` for several built-in
114/// types.
115///
116///   * **i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32,
117///     f64, bool, IpAddr, Ipv4Addr, Ipv6Addr**
118///
119///     The implementation of `UriDisplay` for these types is identical to the
120///     `Display` implementation.
121///
122///   * **`String`, `&str`, `Cow<str>`**
123///
124///     The string is percent encoded.
125///
126///   * **`&T`, `&mut T`** _where_ **`T: UriDisplay`**
127///
128///     Uses the implementation of `UriDisplay` for `T`.
129///
130/// Rocket implements `UriDisplay<Path>` (but not `UriDisplay<Query>`) for
131/// several built-in types.
132///
133///   * `T` for **`Option<T>`** _where_ **`T: UriDisplay<Path>`**
134///
135///     Uses the implementation of `UriDisplay` for `T::Target`.
136///
137///     When a type of `Option<T>` appears in a route path, use a type of `T` as
138///     the parameter in `uri!`. Note that `Option<T>` itself _does not_
139///     implement `UriDisplay<Path>`.
140///
141///   * `T` for **`Result<T, E>`** _where_ **`T: UriDisplay<Path>`**
142///
143///     Uses the implementation of `UriDisplay` for `T::Target`.
144///
145///     When a type of `Result<T, E>` appears in a route path, use a type of `T`
146///     as the parameter in `uri!`. Note that `Result<T, E>` itself _does not_
147///     implement `UriDisplay<Path>`.
148///
149/// Rocket implements `UriDisplay<Query>` (but not `UriDisplay<Path>`) for
150/// several built-in types.
151///
152///   * **`Form<T>`, `LenientForm<T>`** _where_ **`T: FromUriParam + FromForm`**
153///
154///     Uses the implementation of `UriDisplay` for `T::Target`.
155///
156///     In general, when a type of `Form<T>` is to be displayed as part of a
157///     URI's query, it suffices to derive `UriDisplay` for `T`. Note that any
158///     type that can be converted into a `T` using [`FromUriParam`] can be used
159///     in place of a `Form<T>` in a `uri!` invocation.
160///
161///   * **`Option<T>`** _where_ **`T: UriDisplay<Query>`**
162///
163///     If the `Option` is `Some`, uses the implementation of `UriDisplay` for
164///     `T`. Otherwise, nothing is rendered.
165///
166///   * **`Result<T, E>`** _where_ **`T: UriDisplay<Query>`**
167///
168///     If the `Result` is `Ok`, uses the implementation of `UriDisplay` for
169///     `T`. Otherwise, nothing is rendered.
170///
171/// [`FromUriParam`]: crate::uri::fmt::FromUriParam
172///
173/// # Deriving
174///
175/// Manually implementing `UriDisplay` should be done with care. For most use
176/// cases, deriving `UriDisplay` will suffice:
177///
178/// ```rust
179/// # #[macro_use] extern crate rocket;
180/// # use rocket::http::uri::fmt::{UriDisplay, Query, Path};
181/// // Derives `UriDisplay<Query>`
182/// #[derive(UriDisplayQuery)]
183/// struct User {
184///     name: String,
185///     age: usize,
186/// }
187///
188/// let user = User { name: "Michael Smith".into(), age: 31 };
189/// let uri_string = format!("{}", &user as &dyn UriDisplay<Query>);
190/// assert_eq!(uri_string, "name=Michael%20Smith&age=31");
191///
192/// // Derives `UriDisplay<Path>`
193/// #[derive(UriDisplayPath)]
194/// struct Name(String);
195///
196/// let name = Name("Bob Smith".into());
197/// let uri_string = format!("{}", &name as &dyn UriDisplay<Path>);
198/// assert_eq!(uri_string, "Bob%20Smith");
199/// ```
200///
201/// As long as every field in the structure (or enum for [`UriDisplay<Query>`])
202/// implements `UriDisplay`, the trait can be derived. The implementation calls
203/// [`Formatter::write_named_value()`] for every named field and
204/// [`Formatter::write_value()`] for every unnamed field. See the
205/// [`UriDisplay<Path>`] and [`UriDisplay<Query>`] derive documentation for full
206/// details.
207///
208/// [`Ignorable`]: crate::uri::fmt::Ignorable
209/// [`UriDisplay<Path>`]: ../../../derive.UriDisplayPath.html
210/// [`UriDisplay<Query>`]: ../../../derive.UriDisplayQuery.html
211///
212/// # Implementing
213///
214/// Implementing `UriDisplay` is similar to implementing
215/// [`Display`](std::fmt::Display) with the caveat that extra care must be
216/// taken to ensure that the written string is URI-safe. As mentioned before, in
217/// practice, this means that the string must either be percent-encoded or
218/// consist only of characters that are alphanumeric, "-", ".", "_", or "~".
219///
220/// When manually implementing `UriDisplay` for your types, you should defer to
221/// existing implementations of `UriDisplay` as much as possible. In the example
222/// below, for instance, `Name`'s implementation defers to `String`'s
223/// implementation. To percent-encode a string, use
224/// [`Uri::percent_encode()`](crate::uri::Uri::percent_encode()).
225///
226/// ## Example
227///
228/// The following snippet consists of a `Name` type that implements both
229/// `FromParam` and `UriDisplay<Path>`. The `FromParam` implementation allows
230/// `Name` to be used as the target type of a dynamic parameter, while the
231/// `UriDisplay` implementation allows URIs to be generated for routes with
232/// `Name` as a dynamic path parameter type. Note the custom parsing in the
233/// `FromParam` implementation; as a result of this, a custom (reflexive)
234/// `UriDisplay` implementation is required.
235///
236/// ```rust
237/// # #[macro_use] extern crate rocket;
238/// use rocket::request::FromParam;
239///
240/// struct Name<'r>(&'r str);
241///
242/// const PREFIX: &str = "name:";
243///
244/// impl<'r> FromParam<'r> for Name<'r> {
245///     type Error = &'r str;
246///
247///     /// Validates parameters that start with 'name:', extracting the text
248///     /// after 'name:' as long as there is at least one character.
249///     fn from_param(param: &'r str) -> Result<Self, Self::Error> {
250///         if !param.starts_with(PREFIX) || param.len() < (PREFIX.len() + 1) {
251///             return Err(param);
252///         }
253///
254///         let real_name = &param[PREFIX.len()..];
255///         Ok(Name(real_name))
256///     }
257/// }
258///
259/// use std::fmt;
260/// use rocket::http::impl_from_uri_param_identity;
261/// use rocket::http::uri::fmt::{Formatter, FromUriParam, UriDisplay, Path};
262/// use rocket::response::Redirect;
263///
264/// impl UriDisplay<Path> for Name<'_> {
265///     // Writes the raw string `name:`, which is URI-safe, and then delegates
266///     // to the `UriDisplay` implementation for `str` which ensures that
267///     // string is written in a URI-safe manner. In this case, the string will
268///     // be percent encoded.
269///     fn fmt(&self, f: &mut Formatter<Path>) -> fmt::Result {
270///         f.write_raw("name:")?;
271///         UriDisplay::fmt(&self.0, f)
272///     }
273/// }
274///
275/// impl_from_uri_param_identity!([Path] ('a) Name<'a>);
276///
277/// #[get("/name/<name>")]
278/// fn redirector(name: Name<'_>) -> Redirect {
279///     Redirect::to(uri!(real(name)))
280/// }
281///
282/// #[get("/<name>")]
283/// fn real(name: Name<'_>) -> String {
284///     format!("Hello, {}!", name.0)
285/// }
286///
287/// let uri = uri!(real(Name("Mike Smith".into())));
288/// assert_eq!(uri.path(), "/name:Mike%20Smith");
289/// ```
290pub trait UriDisplay<P: Part> {
291    /// Formats `self` in a URI-safe manner using the given formatter.
292    fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result;
293}
294
295impl<P: Part> fmt::Display for &dyn UriDisplay<P> {
296    #[inline(always)]
297    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298        UriDisplay::fmt(*self, &mut <Formatter<'_, P>>::new(f))
299    }
300}
301
302// Direct implementations: these are the leaves of a call to `UriDisplay::fmt`.
303
304/// Percent-encodes the raw string.
305impl<P: Part> UriDisplay<P> for str {
306    #[inline(always)]
307    fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result {
308        f.write_raw(RawStr::new(self).percent_encode().as_str())
309    }
310}
311
312/// Percent-encodes each segment in the path and normalizes separators.
313impl UriDisplay<Path> for path::Path {
314    fn fmt(&self, f: &mut Formatter<'_, Path>) -> fmt::Result {
315        use std::path::Component;
316
317        for component in self.components() {
318            match component {
319                Component::Prefix(_) | Component::RootDir => continue,
320                _ => f.write_value(&component.as_os_str().to_string_lossy())?
321            }
322        }
323
324        Ok(())
325    }
326}
327
328macro_rules! impl_with_display {
329    ($($T:ty),+ $(,)?) => {$(
330        /// This implementation is identical to the `Display` implementation.
331        impl<P: Part> UriDisplay<P> for $T  {
332            #[inline(always)]
333            fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result {
334                use std::fmt::Write;
335                write!(f, "{}", self)
336            }
337        }
338    )+}
339}
340
341use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
342use std::num::{
343    NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
344    NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
345};
346
347// Keep in-sync with the 'FromUriParam' impls.
348impl_with_display! {
349    i8, i16, i32, i64, i128, isize,
350    u8, u16, u32, u64, u128, usize,
351    f32, f64, bool,
352    IpAddr, Ipv4Addr, Ipv6Addr,
353    NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
354    NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
355}
356
357macro_rules! impl_with_string {
358    ($($T:ty => $f:expr),+ $(,)?) => {$(
359        /// This implementation is identical to a percent-encoded version of the
360        /// `Display` implementation.
361        impl<P: Part> UriDisplay<P> for $T  {
362            #[inline(always)]
363            fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result {
364                let func: fn(&$T) -> Result<String, fmt::Error> = $f;
365                func(self).and_then(|s| s.as_str().fmt(f))
366            }
367        }
368    )+}
369}
370
371use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
372
373// Keep formats in sync with 'FromFormField' impls.
374static DATE_FMT: &[FormatItem<'_>] = format_description!("[year padding:none]-[month]-[day]");
375static TIME_FMT: &[FormatItem<'_>] = format_description!("[hour padding:none]:[minute]:[second]");
376static DATE_TIME_FMT: &[FormatItem<'_>] =
377    format_description!("[year padding:none]-[month]-[day]T[hour padding:none]:[minute]:[second]");
378
379// Keep list in sync with the 'FromUriParam' impls.
380impl_with_string! {
381    time::Date => |d| d.format(&DATE_FMT).map_err(|_| fmt::Error),
382    time::Time => |d| d.format(&TIME_FMT).map_err(|_| fmt::Error),
383    time::PrimitiveDateTime => |d| d.format(&DATE_TIME_FMT).map_err(|_| fmt::Error),
384    SocketAddr => |a| Ok(a.to_string()),
385    SocketAddrV4 => |a| Ok(a.to_string()),
386    SocketAddrV6 => |a| Ok(a.to_string()),
387}
388
389// These are second level implementations: they all defer to an existing
390// implementation. Keep in-sync with `FromUriParam` impls.
391
392/// Percent-encodes the raw string. Defers to `str`.
393impl<P: Part> UriDisplay<P> for String {
394    #[inline(always)]
395    fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result {
396        self.as_str().fmt(f)
397    }
398}
399
400/// Percent-encodes the raw string. Defers to `str`.
401impl<P: Part> UriDisplay<P> for Cow<'_, str> {
402    #[inline(always)]
403    fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result {
404        self.as_ref().fmt(f)
405    }
406}
407
408/// Percent-encodes each segment in the path and normalizes separators.
409impl UriDisplay<Path> for path::PathBuf {
410    #[inline(always)]
411    fn fmt(&self, f: &mut Formatter<'_, Path>) -> fmt::Result {
412        self.as_path().fmt(f)
413    }
414}
415
416/// Defers to the `UriDisplay<P>` implementation for `T`.
417impl<P: Part, T: UriDisplay<P> + ?Sized> UriDisplay<P> for &T {
418    #[inline(always)]
419    fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result {
420        UriDisplay::fmt(*self, f)
421    }
422}
423
424/// Defers to the `UriDisplay<P>` implementation for `T`.
425impl<P: Part, T: UriDisplay<P> + ?Sized> UriDisplay<P> for &mut T {
426    #[inline(always)]
427    fn fmt(&self, f: &mut Formatter<'_, P>) -> fmt::Result {
428        UriDisplay::fmt(*self, f)
429    }
430}
431
432/// Defers to the `UriDisplay<Query>` implementation for `T`.
433impl<T: UriDisplay<Query>> UriDisplay<Query> for Option<T> {
434    #[inline(always)]
435    fn fmt(&self, f: &mut Formatter<'_, Query>) -> fmt::Result {
436        match self {
437            Some(v) => v.fmt(f),
438            None => Ok(())
439        }
440    }
441}
442
443/// Defers to the `UriDisplay<Query>` implementation for `T`.
444impl<T: UriDisplay<Query>, E> UriDisplay<Query> for Result<T, E> {
445    #[inline(always)]
446    fn fmt(&self, f: &mut Formatter<'_, Query>) -> fmt::Result {
447        match self {
448            Ok(v) => v.fmt(f),
449            Err(_) => Ok(())
450        }
451    }
452}
453
454impl<T: UriDisplay<Query>> UriDisplay<Query> for Vec<T> {
455    fn fmt(&self, f: &mut Formatter<'_, Query>) -> fmt::Result {
456        self.iter().try_for_each(|v| f.write_value(v))
457    }
458}
459
460impl<T: UriDisplay<Query>, const N: usize> UriDisplay<Query> for [T; N] {
461    fn fmt(&self, f: &mut Formatter<'_, Query>) -> fmt::Result {
462        self.iter().try_for_each(|v| f.write_value(v))
463    }
464}
465
466impl UriDisplay<Query> for [u8] {
467    fn fmt(&self, f: &mut Formatter<'_, Query>) -> fmt::Result {
468        f.write_raw(RawStr::percent_encode_bytes(self).as_str())
469    }
470}
471
472impl<K: UriDisplay<Query>, V: UriDisplay<Query>> UriDisplay<Query> for HashMap<K, V> {
473    fn fmt(&self, f: &mut Formatter<'_, Query>) -> fmt::Result {
474        use std::fmt::Write;
475
476        let mut field_name = String::with_capacity(8);
477        for (i, (key, value)) in self.iter().enumerate() {
478            field_name.truncate(0);
479            write!(field_name, "k:{}", i)?;
480            f.write_named_value(&field_name, key)?;
481
482            field_name.replace_range(..1, "v");
483            f.write_named_value(&field_name, value)?;
484        }
485
486        Ok(())
487    }
488}
489
490impl<K: UriDisplay<Query>, V: UriDisplay<Query>> UriDisplay<Query> for BTreeMap<K, V> {
491    fn fmt(&self, f: &mut Formatter<'_, Query>) -> fmt::Result {
492        use std::fmt::Write;
493
494        let mut field_name = String::with_capacity(8);
495        for (i, (key, value)) in self.iter().enumerate() {
496            field_name.truncate(0);
497            write!(field_name, "k:{}", i)?;
498            f.write_named_value(&field_name, key)?;
499
500            field_name.replace_range(..1, "v");
501            f.write_named_value(&field_name, value)?;
502        }
503
504        Ok(())
505    }
506}
507
508#[cfg(feature = "uuid")] impl_with_display!(uuid_::Uuid);
509#[cfg(feature = "uuid")] crate::impl_from_uri_param_identity!(uuid_::Uuid);
510
511// And finally, the `Ignorable` trait, which has sugar of `_` in the `uri!`
512// macro, which expands to a typecheck.
513
514/// Trait implemented by types that can be ignored in `uri!`.
515///
516/// When a parameter is explicitly ignored in `uri!` by supplying `_` as the
517/// parameter's value, that parameter's type is required to implement this
518/// trait for the corresponding `Part`.
519///
520/// ```rust
521/// # #[macro_use] extern crate rocket;
522/// #[get("/item/<id>?<track>")]
523/// fn get_item(id: i32, track: Option<u8>) { /* .. */ }
524///
525/// // Ignore the `track` parameter: `Option<u8>` must be `Ignorable`.
526/// uri!(get_item(100, _));
527/// uri!(get_item(id = 100, track = _));
528///
529/// // Provide a value for `track`.
530/// uri!(get_item(100, Some(4)));
531/// uri!(get_item(id = 100, track = Some(4)));
532/// ```
533///
534/// # Implementations
535///
536/// Only `Option<T>` and `Result<T, E>` implement this trait. You may implement
537/// this trait for your own ignorable types as well:
538///
539/// ```rust
540/// # #[macro_use] extern crate rocket;
541/// use rocket::http::uri::fmt::{Ignorable, Query};
542///
543/// # struct MyType;
544/// impl Ignorable<Query> for MyType { }
545/// ```
546pub trait Ignorable<P: Part> { }
547
548impl<T> Ignorable<Query> for Option<T> { }
549impl<T, E> Ignorable<Query> for Result<T, E> { }
550
551#[doc(hidden)]
552pub fn assert_ignorable<P: Part, T: Ignorable<P>>() {  }
553
554#[cfg(test)]
555mod uri_display_tests {
556    use std::path;
557    use crate::uri::fmt::{FromUriParam, UriDisplay};
558    use crate::uri::fmt::{Query, Path};
559
560    macro_rules! uri_display {
561        (<$P:ident, $Target:ty> $source:expr) => ({
562            let tmp = $source;
563            let target = <$Target as FromUriParam<$P, _>>::from_uri_param(tmp);
564            format!("{}", &target as &dyn UriDisplay<$P>)
565        })
566    }
567
568    macro_rules! assert_display {
569        (<$P:ident, $Target:ty> $source:expr, $expected:expr) => ({
570            assert_eq!(uri_display!(<$P, $Target> $source), $expected);
571        })
572    }
573
574    #[test]
575    fn uri_display_encoding() {
576        assert_display!(<Query, String> "hello", "hello");
577        assert_display!(<Query, String> "hi hi", "hi%20hi");
578        assert_display!(<Query, &str> "hi hi", "hi%20hi");
579        assert_display!(<Query, &str> &"hi hi", "hi%20hi");
580        assert_display!(<Query, usize> 10, "10");
581        assert_display!(<Query, u8> 10, "10");
582        assert_display!(<Query, i32> 10, "10");
583        assert_display!(<Query, isize> 10, "10");
584
585        assert_display!(<Path, String> "hello", "hello");
586        assert_display!(<Path, String> "hi hi", "hi%20hi");
587        assert_display!(<Path, &str> "hi hi", "hi%20hi");
588        assert_display!(<Path, &str> &"hi hi", "hi%20hi");
589        assert_display!(<Path, usize> 10, "10");
590        assert_display!(<Path, u8> 10, "10");
591        assert_display!(<Path, i32> 10, "10");
592        assert_display!(<Path, isize> 10, "10");
593
594        assert_display!(<Query, &str> &"hi there", "hi%20there");
595        assert_display!(<Query, isize> &10, "10");
596        assert_display!(<Query, u8> &10, "10");
597
598        assert_display!(<Path, &str> &"hi there", "hi%20there");
599        assert_display!(<Path, isize> &10, "10");
600        assert_display!(<Path, u8> &10, "10");
601
602        assert_display!(<Path, Option<&str>> &"hi there", "hi%20there");
603        assert_display!(<Path, Option<isize>> &10, "10");
604        assert_display!(<Path, Option<u8>> &10, "10");
605        assert_display!(<Query, Option<&str>> Some(&"hi there"), "hi%20there");
606        assert_display!(<Query, Option<isize>> Some(&10), "10");
607        assert_display!(<Query, Option<u8>> Some(&10), "10");
608
609        assert_display!(<Path, Result<&str, usize>> &"hi there", "hi%20there");
610        assert_display!(<Path, Result<isize, &str>> &10, "10");
611        assert_display!(<Path, Result<u8, String>> &10, "10");
612        assert_display!(<Query, Result<&str, usize>> Ok(&"hi there"), "hi%20there");
613        assert_display!(<Query, Result<isize, &str>> Ok(&10), "10");
614        assert_display!(<Query, Result<u8, String>> Ok(&10), "10");
615    }
616
617    #[test]
618    fn paths() {
619        assert_display!(<Path, path::PathBuf> "hello", "hello");
620        assert_display!(<Path, path::PathBuf> "hi there", "hi%20there");
621        assert_display!(<Path, path::PathBuf> "hello/world", "hello/world");
622        assert_display!(<Path, path::PathBuf> "hello//world", "hello/world");
623        assert_display!(<Path, path::PathBuf> "hello/ world", "hello/%20world");
624
625        assert_display!(<Path, path::PathBuf> "hi/wo rld", "hi/wo%20rld");
626
627        assert_display!(<Path, path::PathBuf> &"hi/wo rld", "hi/wo%20rld");
628        assert_display!(<Path, path::PathBuf> &"hi there", "hi%20there");
629    }
630
631    struct Wrapper<T>(T);
632
633    impl<A, T: FromUriParam<Query, A>> FromUriParam<Query, A> for Wrapper<T> {
634        type Target = T::Target;
635
636        #[inline(always)]
637        fn from_uri_param(param: A) -> Self::Target {
638            T::from_uri_param(param)
639        }
640    }
641
642    impl FromUriParam<Path, usize> for Wrapper<usize> {
643        type Target = usize;
644
645        #[inline(always)]
646        fn from_uri_param(param: usize) -> Self::Target {
647            param
648        }
649    }
650
651    #[test]
652    fn uri_display_encoding_wrapped() {
653        assert_display!(<Query, Option<Wrapper<&str>>> Some(&"hi there"), "hi%20there");
654        assert_display!(<Query, Option<Wrapper<&str>>> Some("hi there"), "hi%20there");
655
656        assert_display!(<Query, Option<Wrapper<isize>>> Some(10), "10");
657        assert_display!(<Query, Option<Wrapper<usize>>> Some(18), "18");
658        assert_display!(<Path, Option<Wrapper<usize>>> 238, "238");
659
660        assert_display!(<Path, Result<Option<Wrapper<usize>>, usize>> 238, "238");
661        assert_display!(<Path, Option<Result<Wrapper<usize>, usize>>> 123, "123");
662    }
663
664    #[test]
665    fn check_ignorables() {
666        use crate::uri::fmt::assert_ignorable;
667
668        assert_ignorable::<Query, Option<usize>>();
669        assert_ignorable::<Query, Option<Wrapper<usize>>>();
670        assert_ignorable::<Query, Result<Wrapper<usize>, usize>>();
671        assert_ignorable::<Query, Option<Result<Wrapper<usize>, usize>>>();
672        assert_ignorable::<Query, Result<Option<Wrapper<usize>>, usize>>();
673    }
674}