Trait rocket::http::uri::fmt::UriDisplay

source ·
pub trait UriDisplay<P>where
    P: Part,{
    // Required method
    fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>;
}
Expand description

Trait implemented by types that can be displayed as part of a URI in uri!.

Types implementing this trait can be displayed in a URI-safe manner. Unlike Display, the string written by a UriDisplay implementation must be URI-safe. In practice, this means that the string must either be percent-encoded or consist only of characters that are alphanumeric, “-”, “.”, “_”, or “~” - the “unreserved” characters.

Marker Generic: Path, Query

The Part parameter P in UriDisplay<P> must be either Path or Query (see the Part documentation for how this is enforced), resulting in either UriDisplay<Path> or UriDisplay<Query>.

As the names might imply, the Path version of the trait is used when displaying parameters in the path part of the URI while the Query version is used when displaying parameters in the query part of the URI. These distinct versions of the trait exist exactly to differentiate, at the type-level, where in the URI a value is to be written to, allowing for type safety in the face of differences between the two locations. For example, while it is valid to use a value of None in the query part, omitting the parameter entirely, doing so is not valid in the path part. By differentiating in the type system, both of these conditions can be enforced appropriately through distinct implementations of UriDisplay<Path> and UriDisplay<Query>.

Occasionally, the implementation of UriDisplay is independent of where the parameter is to be displayed. When this is the case, the parameter may be kept generic. That is, implementations can take the form:

impl<P: Part> UriDisplay<P> for SomeType

Code Generation

When the uri! macro is used to generate a URI for a route, the types for the route’s path URI parameters must implement UriDisplay<Path>, while types in the route’s query parameters must implement UriDisplay<Query>. Any parameters ignored with _ must be of a type that implements Ignorable. The UriDisplay implementation for these types is used when generating the URI.

To illustrate UriDisplay’s role in code generation for uri!, consider the following route:

#[get("/item/<id>?<track>")]
fn get_item(id: i32, track: Option<String>) { /* .. */ }

A URI for this route can be generated as follows:

// With unnamed parameters.
uri!(get_item(100, Some("inbound")));

// With named parameters.
uri!(get_item(id = 100, track = Some("inbound")));
uri!(get_item(track = Some("inbound"), id = 100));

// Ignoring `track`.
uri!(get_item(100, _));
uri!(get_item(100, None as Option<String>));
uri!(get_item(id = 100, track = _));
uri!(get_item(track = _, id = 100));
uri!(get_item(id = 100, track = None as Option<&str>));

After verifying parameters and their types, Rocket will generate code similar (in spirit) to the following:

Origin::parse(&format!("/item/{}?track={}",
    &100 as &dyn UriDisplay<Path>, &"inbound" as &dyn UriDisplay<Query>));

For this expression to typecheck, i32 must implement UriDisplay<Path> and &str must implement UriDisplay<Query>. What’s more, when track is ignored, Option<String> is required to implement Ignorable. As can be seen, the implementations will be used to display the value in a URI-safe manner.

Provided Implementations

Rocket implements UriDisplay<P> for all P: Part for several built-in types.

  • i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, bool, IpAddr, Ipv4Addr, Ipv6Addr

    The implementation of UriDisplay for these types is identical to the Display implementation.

  • String, &str, Cow<str>

    The string is percent encoded.

  • &T, &mut T where T: UriDisplay

    Uses the implementation of UriDisplay for T.

Rocket implements UriDisplay<Path> (but not UriDisplay<Query>) for several built-in types.

  • T for Option<T> where T: UriDisplay<Path>

    Uses the implementation of UriDisplay for T::Target.

    When a type of Option<T> appears in a route path, use a type of T as the parameter in uri!. Note that Option<T> itself does not implement UriDisplay<Path>.

  • T for Result<T, E> where T: UriDisplay<Path>

    Uses the implementation of UriDisplay for T::Target.

    When a type of Result<T, E> appears in a route path, use a type of T as the parameter in uri!. Note that Result<T, E> itself does not implement UriDisplay<Path>.

Rocket implements UriDisplay<Query> (but not UriDisplay<Path>) for several built-in types.

  • Form<T>, LenientForm<T> where T: FromUriParam + FromForm

    Uses the implementation of UriDisplay for T::Target.

    In general, when a type of Form<T> is to be displayed as part of a URI’s query, it suffices to derive UriDisplay for T. Note that any type that can be converted into a T using FromUriParam can be used in place of a Form<T> in a uri! invocation.

  • Option<T> where T: UriDisplay<Query>

    If the Option is Some, uses the implementation of UriDisplay for T. Otherwise, nothing is rendered.

  • Result<T, E> where T: UriDisplay<Query>

    If the Result is Ok, uses the implementation of UriDisplay for T. Otherwise, nothing is rendered.

Deriving

Manually implementing UriDisplay should be done with care. For most use cases, deriving UriDisplay will suffice:

// Derives `UriDisplay<Query>`
#[derive(UriDisplayQuery)]
struct User {
    name: String,
    age: usize,
}

let user = User { name: "Michael Smith".into(), age: 31 };
let uri_string = format!("{}", &user as &dyn UriDisplay<Query>);
assert_eq!(uri_string, "name=Michael%20Smith&age=31");

// Derives `UriDisplay<Path>`
#[derive(UriDisplayPath)]
struct Name(String);

let name = Name("Bob Smith".into());
let uri_string = format!("{}", &name as &dyn UriDisplay<Path>);
assert_eq!(uri_string, "Bob%20Smith");

As long as every field in the structure (or enum for UriDisplay<Query>) implements UriDisplay, the trait can be derived. The implementation calls Formatter::write_named_value() for every named field and Formatter::write_value() for every unnamed field. See the UriDisplay<Path> and UriDisplay<Query> derive documentation for full details.

Implementing

Implementing UriDisplay is similar to implementing Display with the caveat that extra care must be taken to ensure that the written string is URI-safe. As mentioned before, in practice, this means that the string must either be percent-encoded or consist only of characters that are alphanumeric, “-”, “.”, “_”, or “~”.

When manually implementing UriDisplay for your types, you should defer to existing implementations of UriDisplay as much as possible. In the example below, for instance, Name’s implementation defers to String’s implementation. To percent-encode a string, use Uri::percent_encode().

Example

The following snippet consists of a Name type that implements both FromParam and UriDisplay<Path>. The FromParam implementation allows Name to be used as the target type of a dynamic parameter, while the UriDisplay implementation allows URIs to be generated for routes with Name as a dynamic path parameter type. Note the custom parsing in the FromParam implementation; as a result of this, a custom (reflexive) UriDisplay implementation is required.

use rocket::request::FromParam;

struct Name<'r>(&'r str);

const PREFIX: &str = "name:";

impl<'r> FromParam<'r> for Name<'r> {
    type Error = &'r str;

    /// Validates parameters that start with 'name:', extracting the text
    /// after 'name:' as long as there is at least one character.
    fn from_param(param: &'r str) -> Result<Self, Self::Error> {
        if !param.starts_with(PREFIX) || param.len() < (PREFIX.len() + 1) {
            return Err(param);
        }

        let real_name = &param[PREFIX.len()..];
        Ok(Name(real_name))
    }
}

use std::fmt;
use rocket::http::impl_from_uri_param_identity;
use rocket::http::uri::fmt::{Formatter, FromUriParam, UriDisplay, Path};
use rocket::response::Redirect;

impl UriDisplay<Path> for Name<'_> {
    // Writes the raw string `name:`, which is URI-safe, and then delegates
    // to the `UriDisplay` implementation for `str` which ensures that
    // string is written in a URI-safe manner. In this case, the string will
    // be percent encoded.
    fn fmt(&self, f: &mut Formatter<Path>) -> fmt::Result {
        f.write_raw("name:")?;
        UriDisplay::fmt(&self.0, f)
    }
}

impl_from_uri_param_identity!([Path] ('a) Name<'a>);

#[get("/name/<name>")]
fn redirector(name: Name<'_>) -> Redirect {
    Redirect::to(uri!(real(name)))
}

#[get("/<name>")]
fn real(name: Name<'_>) -> String {
    format!("Hello, {}!", name.0)
}

let uri = uri!(real(Name("Mike Smith".into())));
assert_eq!(uri.path(), "/name:Mike%20Smith");

Required Methods§

source

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

Formats self in a URI-safe manner using the given formatter.

Trait Implementations§

source§

impl<P> Display for &dyn UriDisplay<P>where P: Part,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Implementations on Foreign Types§

source§

impl<K, V> UriDisplay<Query> for HashMap<K, V, RandomState>where K: UriDisplay<Query>, V: UriDisplay<Query>,

source§

fn fmt(&self, f: &mut Formatter<'_, Query>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for i8where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for u128where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroU8where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P, T> UriDisplay<P> for &mut Twhere P: Part, T: UriDisplay<P> + ?Sized,

Defers to the UriDisplay<P> implementation for T.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroI64where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for IpAddrwhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for strwhere P: Part,

Percent-encodes the raw string.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl UriDisplay<Path> for PathBuf

Percent-encodes each segment in the path and normalizes separators.

source§

fn fmt(&self, f: &mut Formatter<'_, Path>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for Ipv6Addrwhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroI16where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for f64where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for u16where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for f32where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroU64where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for Cow<'_, str>where P: Part,

Percent-encodes the raw string. Defers to str.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for i32where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for boolwhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for PrimitiveDateTimewhere P: Part,

This implementation is identical to a percent-encoded version of the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P, T> UriDisplay<P> for &Twhere P: Part, T: UriDisplay<P> + ?Sized,

Defers to the UriDisplay<P> implementation for T.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for Ipv4Addrwhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for SocketAddrwhere P: Part,

This implementation is identical to a percent-encoded version of the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for SocketAddrV4where P: Part,

This implementation is identical to a percent-encoded version of the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for SocketAddrV6where P: Part,

This implementation is identical to a percent-encoded version of the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<T> UriDisplay<Query> for Option<T>where T: UriDisplay<Query>,

Defers to the UriDisplay<Query> implementation for T.

source§

fn fmt(&self, f: &mut Formatter<'_, Query>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroI8where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroI128where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for i16where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroU128where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<T, E> UriDisplay<Query> for Result<T, E>where T: UriDisplay<Query>,

Defers to the UriDisplay<Query> implementation for T.

source§

fn fmt(&self, f: &mut Formatter<'_, Query>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for isizewhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for u8where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for i128where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroUsizewhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for usizewhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroU32where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for Timewhere P: Part,

This implementation is identical to a percent-encoded version of the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<T> UriDisplay<Query> for Vec<T, Global>where T: UriDisplay<Query>,

source§

fn fmt(&self, f: &mut Formatter<'_, Query>) -> Result<(), Error>

source§

impl UriDisplay<Path> for Path

Percent-encodes each segment in the path and normalizes separators.

source§

fn fmt(&self, f: &mut Formatter<'_, Path>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroU16where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for Stringwhere P: Part,

Percent-encodes the raw string. Defers to str.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<K, V> UriDisplay<Query> for BTreeMap<K, V, Global>where K: UriDisplay<Query>, V: UriDisplay<Query>,

source§

fn fmt(&self, f: &mut Formatter<'_, Query>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroIsizewhere P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for u32where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for u64where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for i64where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for NonZeroI32where P: Part,

This implementation is identical to the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

source§

impl<P> UriDisplay<P> for Datewhere P: Part,

This implementation is identical to a percent-encoded version of the Display implementation.

source§

fn fmt(&self, f: &mut Formatter<'_, P>) -> Result<(), Error>

Implementors§