rocket_http_community/uri/fmt/
from_uri_param.rs

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