rocket_http/uri/fmt/
from_uri_param.rs

1use std::collections::{BTreeMap, HashMap};
2use std::path::{Path, PathBuf};
3
4use crate::uri::fmt::UriDisplay;
5use crate::uri::fmt::{self, Part};
6
7/// Conversion trait for parameters used in [`uri!`] invocations.
8///
9/// # Overview
10///
11/// In addition to implementing [`UriDisplay`], to use a custom type in a `uri!`
12/// expression, the `FromUriParam` trait must be implemented. The `UriDisplay`
13/// derive automatically generates _identity_ implementations of `FromUriParam`,
14/// so in the majority of cases, as with `UriDisplay`, this trait is never
15/// implemented manually.
16///
17/// In the rare case that `UriDisplay` is implemented manually, this trait, too,
18/// must be implemented explicitly. In the majority of cases, implementation can
19/// be automated. Rocket provides [`impl_from_uri_param_identity!`] to generate
20/// the _identity_ implementations automatically. For a type `T`, these are:
21///
22///   * `impl<P: Part> FromUriParam<P, T> for T`
23///   * `impl<'x, P: Part> FromUriParam<P, &'x T> for T`
24///   * `impl<'x, P: Part> FromUriParam<P, &'x mut T> for T`
25///
26/// See [`impl_from_uri_param_identity!`] for usage details.
27///
28/// [`impl_from_uri_param_identity!`]: crate::impl_from_uri_param_identity!
29///
30/// # Code Generation
31///
32/// This trait is invoked once per expression passed into a [`uri!`] invocation.
33/// In particular, for a route URI parameter of type `T` and a user-supplied
34/// expression `e` of type `S`, `<T as FromUriParam<S>>::from_uri_param(e)` is
35/// invoked. The returned value of type `T::Target` is used in place of the
36/// user's value and rendered using its [`UriDisplay`] implementation.
37///
38/// This trait allows types that differ from the route URI parameter's types to
39/// be used in their place at no cost. For instance, the following
40/// implementation, provided by Rocket, allows an `&str` to be used in a `uri!`
41/// invocation for route URI parameters declared as `String`:
42///
43/// ```rust
44/// # extern crate rocket;
45/// # use rocket::http::uri::fmt::{FromUriParam, Part};
46/// # struct S;
47/// # type String = S;
48/// impl<'a, P: Part> FromUriParam<P, &'a str> for String {
49///     type Target = &'a str;
50/// #   fn from_uri_param(s: &'a str) -> Self::Target { "hi" }
51/// }
52/// ```
53///
54/// Because the [`FromUriParam::Target`] type is the same as the input type, the
55/// conversion is a no-op and free of cost, allowing an `&str` to be used in
56/// place of a `String` without penalty.
57///
58/// # Provided Implementations
59///
60/// The following types have _identity_ implementations:
61///
62///    * `String`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `u8`, `u16`,
63///      `u32`, `u64`, `u128`, `usize`, `f32`, `f64`, `bool`, `IpAddr`,
64///      `Ipv4Addr`, `Ipv6Addr`, `&str`, `Cow<str>`
65///
66/// The following types have _identity_ implementations _only in [`Path`]_:
67///
68///   * `&Path`, `PathBuf`
69///
70/// The following types have _identity_ implementations _only in [`Query`]_:
71///
72///   * `Option<T>`, `Result<T, E>`
73///
74/// The following conversions are implemented for both paths and queries,
75/// allowing a value of the type on the left to be used when a type on the right
76/// is expected by a route:
77///
78///   * `&str` to `String`
79///   * `String` to `&str`
80///   * `T` to `Form<T>`
81///
82/// The following conversions are implemented _only in [`Path`]_:
83///
84///   * `&str` to `&Path`
85///   * `&str` to `PathBuf`
86///   * `PathBuf` to `&Path`
87///   * `T` to `Option<T>`
88///   * `T` to `Result<T, E>`
89///
90/// The following conversions are implemented _only in [`Query`]_:
91///
92///   * `Option<T>` to `Result<T, E>` (for any `E`)
93///   * `Result<T, E>` to `Option<T>` (for any `E`)
94///
95/// See [Foreign Impls](#foreign-impls) for all provided implementations.
96///
97/// # Implementing
98///
99/// This trait should only be implemented when you'd like to allow a type
100/// different from the route's declared type to be used in its place in a `uri!`
101/// invocation. For instance, if the route has a type of `T` and you'd like to
102/// use a type of `S` in a `uri!` invocation, you'd implement `FromUriParam<P,
103/// T> for S` where `P` is `Path` for conversions valid in the path part of a
104/// URI, `Uri` for conversions valid in the query part of a URI, or `P: Part`
105/// when a conversion is valid in either case.
106///
107/// This is typically only warranted for owned-value types with corresponding
108/// reference types: `String` and `&str`, for instance. In this case, it's
109/// desirable to allow an `&str` to be used in place of a `String`.
110///
111/// When implementing `FromUriParam`, be aware that Rocket will use the
112/// [`UriDisplay`] implementation of [`FromUriParam::Target`], _not_ of the
113/// source type. Incorrect implementations can result in creating unsafe URIs.
114///
115/// # Example
116///
117/// The following example implements `FromUriParam<Query, (&str, &str)>` for a
118/// `User` type. The implementation allows an `(&str, &str)` type to be used in
119/// a `uri!` invocation where a `User` type is expected in the query part of the
120/// URI.
121///
122/// ```rust
123/// # #[macro_use] extern crate rocket;
124/// use std::fmt;
125///
126/// use rocket::http::uri::fmt::{Formatter, UriDisplay, FromUriParam, Query};
127///
128/// #[derive(FromForm)]
129/// struct User<'a> {
130///     name: &'a str,
131///     nickname: String,
132/// }
133///
134/// impl UriDisplay<Query> for User<'_> {
135///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
136///         f.write_named_value("name", &self.name)?;
137///         f.write_named_value("nickname", &self.nickname)
138///     }
139/// }
140///
141/// impl<'a, 'b> FromUriParam<Query, (&'a str, &'b str)> for User<'a> {
142///     type Target = User<'a>;
143///
144///     fn from_uri_param((name, nickname): (&'a str, &'b str)) -> User<'a> {
145///         User { name: name.into(), nickname: nickname.to_string() }
146///     }
147/// }
148/// ```
149///
150/// With these implementations, the following typechecks:
151///
152/// ```rust
153/// # #[macro_use] extern crate rocket;
154/// # use std::fmt;
155/// # use rocket::http::uri::fmt::{Formatter, UriDisplay, FromUriParam, Query};
156/// #
157/// # #[derive(FromForm)]
158/// # struct User<'a> { name: &'a str, nickname: String, }
159/// #
160/// # impl UriDisplay<Query> for User<'_> {
161/// #     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
162/// #         f.write_named_value("name", &self.name)?;
163/// #         f.write_named_value("nickname", &self.nickname)
164/// #     }
165/// # }
166/// #
167/// # impl<'a, 'b> FromUriParam<Query, (&'a str, &'b str)> for User<'a> {
168/// #     type Target = User<'a>;
169/// #     fn from_uri_param((name, nickname): (&'a str, &'b str)) -> User<'a> {
170/// #         User { name: name.into(), nickname: nickname.to_string() }
171/// #     }
172/// # }
173/// #
174/// #[post("/<name>?<user..>")]
175/// fn some_route(name: &str, user: User<'_>)  { /* .. */ }
176///
177/// let uri = uri!(some_route(name = "hey", user = ("Robert Mike", "Bob")));
178/// assert_eq!(uri.path(), "/hey");
179/// assert_eq!(uri.query().unwrap(), "name=Robert%20Mike&nickname=Bob");
180/// ```
181///
182/// [`uri!`]: ../../../../rocket/macro.uri.html
183/// [`FromUriParam::Target`]: crate::uri::fmt::FromUriParam::Target
184/// [`Path`]: crate::uri::fmt::Path
185/// [`Query`]: crate::uri::fmt::Query
186pub trait FromUriParam<P: Part, T> {
187    /// The resulting type of this conversion.
188    type Target: UriDisplay<P>;
189
190    /// Converts a value of type `T` into a value of type `Self::Target`. The
191    /// resulting value of type `Self::Target` will be rendered into a URI using
192    /// its [`UriDisplay`] implementation.
193    fn from_uri_param(param: T) -> Self::Target;
194}
195
196#[doc(hidden)]
197#[macro_export(local_inner_macros)]
198macro_rules! impl_conversion_ref {
199    ($(($($l:tt)+) $A:ty => $B:ty),* $(,)?) => (
200        impl_conversion_ref!(@_ $(($($l)+,) $A => $B),*);
201    );
202
203    ($($A:ty => $B:ty),* $(,)?) => (
204        impl_conversion_ref!(@_ $(() $A => $B),*);
205    );
206
207    (@_ $(($($l:tt)*) $A:ty => $B:ty),* $(,)?) => ($(
208        impl_conversion_ref!([P] ($($l)* P: $crate::uri::fmt::Part) $A => $B);
209    )*);
210
211    ($([$P:ty] ($($l:tt)*) $A:ty => $B:ty),* $(,)?) => ($(
212        impl_conversion_ref!(@_ [$P] ($($l)*) $A => $B);
213        impl_conversion_ref!(@_ [$P] ('x, $($l)*) &'x $A => $B);
214        impl_conversion_ref!(@_ [$P] ('x, $($l)*) &'x mut $A => $B);
215    )*);
216
217    ($([$P:ty] $A:ty => $B:ty),* $(,)?) => ( impl_conversion_ref!($([$P] () $A => $B),*););
218
219    (@_ [$P:ty] ($($l:tt)*) $A:ty => $B:ty) => (
220        impl<$($l)*> $crate::uri::fmt::FromUriParam<$P, $A> for $B {
221            type Target = $A;
222            #[inline(always)] fn from_uri_param(param: $A) -> $A { param }
223        }
224    );
225}
226
227/// Macro to automatically generate _identity_ [`FromUriParam`] trait
228/// implementations.
229///
230/// For a type `T`, the _identity_ implementations of `FromUriParam` are:
231///
232///   * `impl<P: Part> FromUriParam<P, T> for T`
233///   * `impl<'x> FromUriParam<P, &'x T> for T`
234///   * `impl<'x> FromUriParam<P, &'x mut T> for T`
235///
236/// where `P` is one of:
237///
238///   * `P: Part` (the generic `P`)
239///   * [`Path`]
240///   * [`Query`]
241///
242/// This macro can be invoked in four ways:
243///
244///   1. `impl_from_uri_param_identity!(Type);`
245///
246///      Generates the three _identity_ implementations for the generic `P`.
247///
248///      * Example: `impl_from_uri_param_identity!(MyType);`
249///      * Generates: `impl<P: Part> FromUriParam<P, _> for MyType { ... }`
250///
251///   2. `impl_from_uri_param_identity!((generics*) Type);`
252///
253///      Generates the three _identity_ implementations for the generic `P`,
254///      adding the tokens `generics` to the `impl` generics of the generated
255///      implementation.
256///
257///      * Example: `impl_from_uri_param_identity!(('a) MyType<'a>);`
258///      * Generates: `impl<'a, P: Part> FromUriParam<P, _> for MyType<'a> { ... }`
259///
260///   3. `impl_from_uri_param_identity!([Part] Type);`
261///
262///      Generates the three _identity_ implementations for the `Part`
263///      `Part`, where `Part` is a path to [`Path`] or [`Query`].
264///
265///      * Example: `impl_from_uri_param_identity!([Path] MyType);`
266///      * Generates: `impl FromUriParam<Path, _> for MyType { ... }`
267///
268///   4. `impl_from_uri_param_identity!([Part] (generics*) Type);`
269///
270///      See 2 and 3.
271///
272///      * Example: `impl_from_uri_param_identity!([Path] ('a) MyType<'a>);`
273///      * Generates: `impl<'a> FromUriParam<Path, _> for MyType<'a> { ... }`
274///
275/// [`FromUriParam`]: crate::uri::fmt::FromUriParam
276/// [`Path`]: crate::uri::fmt::Path
277/// [`Query`]: crate::uri::fmt::Query
278#[macro_export(local_inner_macros)]
279macro_rules! impl_from_uri_param_identity {
280    ($(($($l:tt)*) $T:ty),* $(,)?) => ($( impl_conversion_ref!(($($l)*) $T => $T); )*);
281    ($([$P:ty] ($($l:tt)*) $T:ty),* $(,)?) => ($( impl_conversion_ref!([$P] ($($l)*) $T => $T); )*);
282    ($([$P:ty] $T:ty),* $(,)?) => ($( impl_conversion_ref!([$P] $T => $T); )*);
283    ($($T:ty),* $(,)?) => ($( impl_conversion_ref!($T => $T); )*);
284}
285
286use std::borrow::Cow;
287use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
288use std::num::{
289    NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
290    NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
291};
292
293impl_from_uri_param_identity! {
294    String,
295    i8, i16, i32, i64, i128, isize,
296    u8, u16, u32, u64, u128, usize,
297    f32, f64, bool,
298    IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6,
299    NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
300    NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
301    time::Date, time::Time, time::PrimitiveDateTime,
302}
303
304impl_from_uri_param_identity! {
305    ('a) &'a str,
306    ('a) Cow<'a, str>
307}
308
309impl_conversion_ref! {
310    ('a) &'a str => String,
311
312    ('a) String => &'a str
313}
314
315impl_from_uri_param_identity!([fmt::Path] ('a) &'a Path);
316impl_from_uri_param_identity!([fmt::Path] PathBuf);
317
318impl_conversion_ref! {
319    [fmt::Path] ('a) &'a Path => PathBuf,
320    [fmt::Path] ('a) PathBuf => &'a Path,
321}
322
323// TODO: A specialized `RawBytes` instead of `&[u8]`. Then impl [T] => Vec<T>.
324impl_from_uri_param_identity!([fmt::Query] ('a) &'a [u8]);
325
326impl_conversion_ref! {
327    [fmt::Query] (T, A: FromUriParam<fmt::Query, T> + UriDisplay<fmt::Query>) Vec<A> => Vec<T>,
328    [fmt::Query] (
329            T,
330            A: FromUriParam<fmt::Query, T> + UriDisplay<fmt::Query>,
331            const N: usize
332        ) Vec<A> => [T; N],
333
334    [fmt::Query] (
335            T,
336            A: FromUriParam<fmt::Query, T> + UriDisplay<fmt::Query>,
337            const N: usize
338        ) [A; N] => Vec<T>,
339
340    [fmt::Query] (
341            T,
342            A: FromUriParam<fmt::Query, T> + UriDisplay<fmt::Query>,
343            const N: usize
344        ) [A; N] => [T; N],
345}
346
347/// A no cost conversion allowing an `&str` to be used in place of a `PathBuf`.
348impl<'a> FromUriParam<fmt::Path, &'a str> for PathBuf {
349    type Target = &'a Path;
350
351    #[inline(always)]
352    fn from_uri_param(param: &'a str) -> &'a Path {
353        Path::new(param)
354    }
355}
356
357/// A no cost conversion allowing an `&&str` to be used in place of a `PathBuf`.
358impl<'a, 'b> FromUriParam<fmt::Path, &'a &'b str> for PathBuf {
359    type Target = &'b Path;
360
361    #[inline(always)]
362    fn from_uri_param(param: &'a &'b str) -> &'b Path {
363        Path::new(*param)
364    }
365}
366
367/// A no cost conversion allowing any `T` to be used in place of an `Option<T>`.
368impl<A, T: FromUriParam<fmt::Path, A>> FromUriParam<fmt::Path, A> for Option<T> {
369    type Target = T::Target;
370
371    #[inline(always)]
372    fn from_uri_param(param: A) -> Self::Target {
373        T::from_uri_param(param)
374    }
375}
376
377/// A no cost conversion allowing `T` to be used in place of an `Result<T, E>`.
378impl<A, E, T: FromUriParam<fmt::Path, A>> FromUriParam<fmt::Path, A> for Result<T, E> {
379    type Target = T::Target;
380
381    #[inline(always)]
382    fn from_uri_param(param: A) -> Self::Target {
383        T::from_uri_param(param)
384    }
385}
386
387impl<A, T: FromUriParam<fmt::Query, A>> FromUriParam<fmt::Query, Option<A>> for Option<T> {
388    type Target = Option<T::Target>;
389
390    #[inline(always)]
391    fn from_uri_param(param: Option<A>) -> Self::Target {
392        param.map(T::from_uri_param)
393    }
394}
395
396impl<A, E, T: FromUriParam<fmt::Query, A>> FromUriParam<fmt::Query, Option<A>> for Result<T, E> {
397    type Target = Option<T::Target>;
398
399    #[inline(always)]
400    fn from_uri_param(param: Option<A>) -> Self::Target {
401        param.map(T::from_uri_param)
402    }
403}
404
405impl<A, E, T: FromUriParam<fmt::Query, A>> FromUriParam<fmt::Query, Result<A, E>> for Result<T, E> {
406    type Target = Result<T::Target, E>;
407
408    #[inline(always)]
409    fn from_uri_param(param: Result<A, E>) -> Self::Target {
410        param.map(T::from_uri_param)
411    }
412}
413
414impl<A, E, T: FromUriParam<fmt::Query, A>> FromUriParam<fmt::Query, Result<A, E>> for Option<T> {
415    type Target = Result<T::Target, E>;
416
417    #[inline(always)]
418    fn from_uri_param(param: Result<A, E>) -> Self::Target {
419        param.map(T::from_uri_param)
420    }
421}
422
423macro_rules! impl_map_conversion {
424    ($From:ident => $To:ident) => (
425        impl<K, V, A, B> FromUriParam<fmt::Query, $From<A, B>> for $To<K, V>
426            where A: UriDisplay<fmt::Query>, K: FromUriParam<fmt::Query, A>,
427                  B: UriDisplay<fmt::Query>, V: FromUriParam<fmt::Query, B>
428        {
429            type Target = $From<A, B>;
430
431            #[inline(always)]
432            fn from_uri_param(param: $From<A, B>) -> Self::Target {
433                param
434            }
435        }
436    );
437
438    (& $([$mut:tt])? $From:ident => $To:ident) => (
439        impl<'a, K, V, A, B> FromUriParam<fmt::Query, &'a $($mut)? $From<A, B>> for $To<K, V>
440            where A: UriDisplay<fmt::Query>, K: FromUriParam<fmt::Query, A>,
441                  B: UriDisplay<fmt::Query>, V: FromUriParam<fmt::Query, B>
442        {
443            type Target = &'a $From<A, B>;
444
445            #[inline(always)]
446            fn from_uri_param(param: &'a $($mut)? $From<A, B>) -> Self::Target {
447                param
448            }
449        }
450    );
451}
452
453impl_map_conversion!(HashMap => HashMap);
454impl_map_conversion!(HashMap => BTreeMap);
455impl_map_conversion!(BTreeMap => BTreeMap);
456impl_map_conversion!(BTreeMap => HashMap);
457
458impl_map_conversion!(&HashMap => HashMap);
459impl_map_conversion!(&HashMap => BTreeMap);
460impl_map_conversion!(&BTreeMap => BTreeMap);
461impl_map_conversion!(&BTreeMap => HashMap);
462
463impl_map_conversion!(&[mut] HashMap => HashMap);
464impl_map_conversion!(&[mut] HashMap => BTreeMap);
465impl_map_conversion!(&[mut] BTreeMap => BTreeMap);
466impl_map_conversion!(&[mut] BTreeMap => HashMap);