rocket_http_community/uri/fmt/
uri_display.rs

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