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);