@@ -102,29 +102,33 @@ use crate::http::uncased::AsUncased;
102
102
/// applications will never need a custom implementation of `FromForm` or
103
103
/// `FromFormField`. Their behavior is documented in the table below.
104
104
///
105
- /// | Type | Strategy | Default | Data | Value | Notes |
106
- /// |--------------------|-------------|-------------------|--------|--------|----------------------------------------------------|
107
- /// | [`Strict<T>`] | **strict** | if `strict` `T` | if `T` | if `T` | `T: FromForm` |
108
- /// | [`Lenient<T>`] | **lenient** | if `lenient` `T` | if `T` | if `T` | `T: FromForm` |
109
- /// | `Option<T>` | **strict** | `None` | if `T` | if `T` | Infallible, `T: FromForm` |
110
- /// | [`Result<T>`] | _inherit_ | `T::finalize()` | if `T` | if `T` | Infallible, `T: FromForm` |
111
- /// | `Vec<T>` | _inherit_ | `vec![]` | if `T` | if `T` | `T: FromForm` |
112
- /// | [`HashMap<K, V>`] | _inherit_ | `HashMap::new()` | if `V` | if `V` | `K: FromForm + Eq + Hash`, `V: FromForm` |
113
- /// | [`BTreeMap<K, V>`] | _inherit_ | `BTreeMap::new()` | if `V` | if `V` | `K: FromForm + Ord`, `V: FromForm` |
114
- /// | `bool` | _inherit_ | `false` | No | Yes | `"yes"/"on"/"true"`, `"no"/"off"/"false"` |
115
- /// | (un)signed int | _inherit_ | **no default** | No | Yes | `{u,i}{size,8,16,32,64,128}` |
116
- /// | _nonzero_ int | _inherit_ | **no default** | No | Yes | `NonZero{I,U}{size,8,16,32,64,128}` |
117
- /// | float | _inherit_ | **no default** | No | Yes | `f{32,64}` |
118
- /// | `&str` | _inherit_ | **no default** | Yes | Yes | Percent-decoded. Data limit `string` applies. |
119
- /// | `&[u8]` | _inherit_ | **no default** | Yes | Yes | Raw bytes. Data limit `bytes` applies. |
120
- /// | `String` | _inherit_ | **no default** | Yes | Yes | Exactly `&str`, but owned. Prefer `&str`. |
121
- /// | IP Address | _inherit_ | **no default** | No | Yes | [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`] |
122
- /// | Socket Address | _inherit_ | **no default** | No | Yes | [`SocketAddr`], [`SocketAddrV4`], [`SocketAddrV6`] |
123
- /// | [`TempFile`] | _inherit_ | **no default** | Yes | Yes | Data limits apply. See [`TempFile`]. |
124
- /// | [`Capped<C>`] | _inherit_ | **no default** | Yes | Yes | `C` is `&str`, `String`, `&[u8]` or `TempFile`. |
125
- /// | [`time::Date`] | _inherit_ | **no default** | No | Yes | `%F` (`YYYY-MM-DD`). HTML "date" input. |
126
- /// | [`time::DateTime`] | _inherit_ | **no default** | No | Yes | `%FT%R` or `%FT%T` (`YYYY-MM-DDTHH:MM[:SS]`) |
127
- /// | [`time::Time`] | _inherit_ | **no default** | No | Yes | `%R` or `%T` (`HH:MM[:SS]`) |
105
+ /// | Type | Strategy | Default | Data | Value | Notes |
106
+ /// |------------------------|-------------|-------------------|--------|--------|----------------------------------------------------|
107
+ /// | [`Strict<T>`] | **strict** | if `strict` `T` | if `T` | if `T` | `T: FromForm` |
108
+ /// | [`Lenient<T>`] | **lenient** | if `lenient` `T` | if `T` | if `T` | `T: FromForm` |
109
+ /// | `Option<T>` | **strict** | `None` | if `T` | if `T` | Infallible, `T: FromForm` |
110
+ /// | [`Result<T>`] | _inherit_ | `T::finalize()` | if `T` | if `T` | Infallible, `T: FromForm` |
111
+ /// | `Vec<T>` | _inherit_ | `vec![]` | if `T` | if `T` | `T: FromForm` |
112
+ /// | [`HashMap<K, V>`] | _inherit_ | `HashMap::new()` | if `V` | if `V` | `K: FromForm + Eq + Hash`, `V: FromForm` |
113
+ /// | [`BTreeMap<K, V>`] | _inherit_ | `BTreeMap::new()` | if `V` | if `V` | `K: FromForm + Ord`, `V: FromForm` |
114
+ /// | [`Range<T>`] | _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `start`, `end` fields |
115
+ /// | [`RangeFrom<T>`] | _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `start` field |
116
+ /// | [`RangeTo<T>`] | _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `end` field |
117
+ /// | [`RangeToInclusive<T>`]| _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `end` field |
118
+ /// | `bool` | _inherit_ | `false` | No | Yes | `"yes"/"on"/"true"`, `"no"/"off"/"false"` |
119
+ /// | (un)signed int | _inherit_ | **no default** | No | Yes | `{u,i}{size,8,16,32,64,128}` |
120
+ /// | _nonzero_ int | _inherit_ | **no default** | No | Yes | `NonZero{I,U}{size,8,16,32,64,128}` |
121
+ /// | float | _inherit_ | **no default** | No | Yes | `f{32,64}` |
122
+ /// | `&str` | _inherit_ | **no default** | Yes | Yes | Percent-decoded. Data limit `string` applies. |
123
+ /// | `&[u8]` | _inherit_ | **no default** | Yes | Yes | Raw bytes. Data limit `bytes` applies. |
124
+ /// | `String` | _inherit_ | **no default** | Yes | Yes | Exactly `&str`, but owned. Prefer `&str`. |
125
+ /// | IP Address | _inherit_ | **no default** | No | Yes | [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`] |
126
+ /// | Socket Address | _inherit_ | **no default** | No | Yes | [`SocketAddr`], [`SocketAddrV4`], [`SocketAddrV6`] |
127
+ /// | [`TempFile`] | _inherit_ | **no default** | Yes | Yes | Data limits apply. See [`TempFile`]. |
128
+ /// | [`Capped<C>`] | _inherit_ | **no default** | Yes | Yes | `C` is `&str`, `String`, `&[u8]` or `TempFile`. |
129
+ /// | [`time::Date`] | _inherit_ | **no default** | No | Yes | `%F` (`YYYY-MM-DD`). HTML "date" input. |
130
+ /// | [`time::DateTime`] | _inherit_ | **no default** | No | Yes | `%FT%R` or `%FT%T` (`YYYY-MM-DDTHH:MM[:SS]`) |
131
+ /// | [`time::Time`] | _inherit_ | **no default** | No | Yes | `%R` or `%T` (`HH:MM[:SS]`) |
128
132
///
129
133
/// [`Result<T>`]: crate::form::Result
130
134
/// [`Strict<T>`]: crate::form::Strict
@@ -140,6 +144,10 @@ use crate::http::uncased::AsUncased;
140
144
/// [`SocketAddr`]: std::net::SocketAddr
141
145
/// [`SocketAddrV4`]: std::net::SocketAddrV4
142
146
/// [`SocketAddrV6`]: std::net::SocketAddrV6
147
+ /// [`Range<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.Range.html
148
+ /// [`RangeFrom<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.RangeFrom.html
149
+ /// [`RangeTo<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.RangeTo.html
150
+ /// [`RangeToInclusive<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.RangeToInclusive.html
143
151
///
144
152
/// ## Additional Notes
145
153
///
@@ -931,3 +939,51 @@ impl<'v, T: FromForm<'v> + Sync> FromForm<'v> for Arc<T> {
931
939
T :: finalize ( this) . map ( Arc :: new)
932
940
}
933
941
}
942
+
943
+ macro_rules! impl_via_proxy {
944
+ ( $R: ident => struct $T: ident <$( $G: ident) ,* > { $( $f: ident : $F: ident) ,* } ) => {
945
+ const _: ( ) = {
946
+ use super :: * ;
947
+
948
+ mod proxy {
949
+ #[ derive( rocket:: FromForm ) ]
950
+ pub struct $T<$( $G) ,* > {
951
+ $( pub $f : $F) ,*
952
+ }
953
+ }
954
+
955
+ #[ crate :: async_trait]
956
+ impl <' v, $( $G: Send ) ,* > FromForm <' v> for $R<$( $G) ,* >
957
+ where proxy:: $T<$( $G) ,* >: FromForm <' v>
958
+ {
959
+ type Context = <proxy:: $T<$( $G) ,* > as FromForm <' v>>:: Context ;
960
+
961
+ fn init( opts: Options ) -> Self :: Context {
962
+ <proxy:: $T<$( $G) ,* >>:: init( opts)
963
+ }
964
+
965
+ fn push_value( ctxt: & mut Self :: Context , field: ValueField <' v>) {
966
+ <proxy:: $T<$( $G) ,* >>:: push_value( ctxt, field)
967
+ }
968
+
969
+ async fn push_data( ctxt: & mut Self :: Context , field: DataField <' v, ' _>) {
970
+ <proxy:: $T<$( $G) ,* >>:: push_data( ctxt, field) . await
971
+ }
972
+
973
+ fn finalize( this: Self :: Context ) -> Result <' v, Self > {
974
+ let proxy = <proxy:: $T<$( $G) ,* >>:: finalize( this) ?;
975
+ Ok ( $R {
976
+ $( $f : proxy. $f) ,*
977
+ } )
978
+ }
979
+ }
980
+ } ;
981
+ }
982
+ }
983
+
984
+ use std:: ops:: { Range , RangeFrom , RangeTo , RangeToInclusive } ;
985
+
986
+ impl_via_proxy ! ( Range => struct Range <T > { start: T , end: T } ) ;
987
+ impl_via_proxy ! ( RangeFrom => struct RangeFrom <T > { start: T } ) ;
988
+ impl_via_proxy ! ( RangeTo => struct RangeTo <T > { end: T } ) ;
989
+ impl_via_proxy ! ( RangeToInclusive => struct RangeToInclusive <T > { end: T } ) ;
0 commit comments