mirror of https://github.com/rwf2/Rocket.git
Impl 'FromForm' for char, 'Range' types.
Implements 'FromForm' for: * `char` * `Range<T: FromForm>` * `RangeFrom<T: FromForm>` * `RangeTo<T: FromForm>` * `RangeToInclusive<T: FromForm>` Resolves #2759.
This commit is contained in:
parent
fd2094c5f3
commit
5f9ff3f3af
|
@ -3,6 +3,7 @@
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
use std::num::{ParseIntError, ParseFloatError};
|
use std::num::{ParseIntError, ParseFloatError};
|
||||||
use std::str::{Utf8Error, ParseBoolError};
|
use std::str::{Utf8Error, ParseBoolError};
|
||||||
|
use std::char::ParseCharError;
|
||||||
use std::net::AddrParseError;
|
use std::net::AddrParseError;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
@ -200,6 +201,8 @@ pub enum ErrorKind<'v> {
|
||||||
Multipart(multer::Error),
|
Multipart(multer::Error),
|
||||||
/// A string was invalid UTF-8.
|
/// A string was invalid UTF-8.
|
||||||
Utf8(Utf8Error),
|
Utf8(Utf8Error),
|
||||||
|
/// A value failed to parse as a char.
|
||||||
|
Char(ParseCharError),
|
||||||
/// A value failed to parse as an integer.
|
/// A value failed to parse as an integer.
|
||||||
Int(ParseIntError),
|
Int(ParseIntError),
|
||||||
/// A value failed to parse as a boolean.
|
/// A value failed to parse as a boolean.
|
||||||
|
@ -857,6 +860,7 @@ impl fmt::Display for ErrorKind<'_> {
|
||||||
ErrorKind::Custom(_, e) => e.fmt(f)?,
|
ErrorKind::Custom(_, e) => e.fmt(f)?,
|
||||||
ErrorKind::Multipart(e) => write!(f, "invalid multipart: {}", e)?,
|
ErrorKind::Multipart(e) => write!(f, "invalid multipart: {}", e)?,
|
||||||
ErrorKind::Utf8(e) => write!(f, "invalid UTF-8: {}", e)?,
|
ErrorKind::Utf8(e) => write!(f, "invalid UTF-8: {}", e)?,
|
||||||
|
ErrorKind::Char(e) => write!(f, "invalid character: {}", e)?,
|
||||||
ErrorKind::Int(e) => write!(f, "invalid integer: {}", e)?,
|
ErrorKind::Int(e) => write!(f, "invalid integer: {}", e)?,
|
||||||
ErrorKind::Bool(e) => write!(f, "invalid boolean: {}", e)?,
|
ErrorKind::Bool(e) => write!(f, "invalid boolean: {}", e)?,
|
||||||
ErrorKind::Float(e) => write!(f, "invalid float: {}", e)?,
|
ErrorKind::Float(e) => write!(f, "invalid float: {}", e)?,
|
||||||
|
@ -885,6 +889,7 @@ impl crate::http::ext::IntoOwned for ErrorKind<'_> {
|
||||||
Custom(s, e) => Custom(s, e),
|
Custom(s, e) => Custom(s, e),
|
||||||
Multipart(e) => Multipart(e),
|
Multipart(e) => Multipart(e),
|
||||||
Utf8(e) => Utf8(e),
|
Utf8(e) => Utf8(e),
|
||||||
|
Char(e) => Char(e),
|
||||||
Int(e) => Int(e),
|
Int(e) => Int(e),
|
||||||
Bool(e) => Bool(e),
|
Bool(e) => Bool(e),
|
||||||
Float(e) => Float(e),
|
Float(e) => Float(e),
|
||||||
|
@ -985,6 +990,7 @@ macro_rules! impl_from_for {
|
||||||
|
|
||||||
impl_from_for!(<'a> Utf8Error => ErrorKind<'a> as Utf8);
|
impl_from_for!(<'a> Utf8Error => ErrorKind<'a> as Utf8);
|
||||||
impl_from_for!(<'a> ParseIntError => ErrorKind<'a> as Int);
|
impl_from_for!(<'a> ParseIntError => ErrorKind<'a> as Int);
|
||||||
|
impl_from_for!(<'a> ParseCharError => ErrorKind<'a> as Char);
|
||||||
impl_from_for!(<'a> ParseFloatError => ErrorKind<'a> as Float);
|
impl_from_for!(<'a> ParseFloatError => ErrorKind<'a> as Float);
|
||||||
impl_from_for!(<'a> ParseBoolError => ErrorKind<'a> as Bool);
|
impl_from_for!(<'a> ParseBoolError => ErrorKind<'a> as Bool);
|
||||||
impl_from_for!(<'a> AddrParseError => ErrorKind<'a> as Addr);
|
impl_from_for!(<'a> AddrParseError => ErrorKind<'a> as Addr);
|
||||||
|
@ -1024,6 +1030,7 @@ impl Entity {
|
||||||
| ErrorKind::OutOfRange { .. }
|
| ErrorKind::OutOfRange { .. }
|
||||||
| ErrorKind::Validation { .. }
|
| ErrorKind::Validation { .. }
|
||||||
| ErrorKind::Utf8(_)
|
| ErrorKind::Utf8(_)
|
||||||
|
| ErrorKind::Char(_)
|
||||||
| ErrorKind::Int(_)
|
| ErrorKind::Int(_)
|
||||||
| ErrorKind::Float(_)
|
| ErrorKind::Float(_)
|
||||||
| ErrorKind::Bool(_)
|
| ErrorKind::Bool(_)
|
||||||
|
|
|
@ -103,7 +103,7 @@ use crate::http::uncased::AsUncased;
|
||||||
/// `FromFormField`. Their behavior is documented in the table below.
|
/// `FromFormField`. Their behavior is documented in the table below.
|
||||||
///
|
///
|
||||||
/// | Type | Strategy | Default | Data | Value | Notes |
|
/// | Type | Strategy | Default | Data | Value | Notes |
|
||||||
/// |--------------------|-------------|-------------------|--------|--------|----------------------------------------------------|
|
/// |------------------------|-------------|-------------------|--------|--------|----------------------------------------------------|
|
||||||
/// | [`Strict<T>`] | **strict** | if `strict` `T` | if `T` | if `T` | `T: FromForm` |
|
/// | [`Strict<T>`] | **strict** | if `strict` `T` | if `T` | if `T` | `T: FromForm` |
|
||||||
/// | [`Lenient<T>`] | **lenient** | if `lenient` `T` | if `T` | if `T` | `T: FromForm` |
|
/// | [`Lenient<T>`] | **lenient** | if `lenient` `T` | if `T` | if `T` | `T: FromForm` |
|
||||||
/// | `Option<T>` | **strict** | `None` | if `T` | if `T` | Infallible, `T: FromForm` |
|
/// | `Option<T>` | **strict** | `None` | if `T` | if `T` | Infallible, `T: FromForm` |
|
||||||
|
@ -111,6 +111,10 @@ use crate::http::uncased::AsUncased;
|
||||||
/// | `Vec<T>` | _inherit_ | `vec![]` | if `T` | if `T` | `T: FromForm` |
|
/// | `Vec<T>` | _inherit_ | `vec![]` | if `T` | if `T` | `T: FromForm` |
|
||||||
/// | [`HashMap<K, V>`] | _inherit_ | `HashMap::new()` | if `V` | if `V` | `K: FromForm + Eq + Hash`, `V: FromForm` |
|
/// | [`HashMap<K, V>`] | _inherit_ | `HashMap::new()` | if `V` | if `V` | `K: FromForm + Eq + Hash`, `V: FromForm` |
|
||||||
/// | [`BTreeMap<K, V>`] | _inherit_ | `BTreeMap::new()` | if `V` | if `V` | `K: FromForm + Ord`, `V: FromForm` |
|
/// | [`BTreeMap<K, V>`] | _inherit_ | `BTreeMap::new()` | if `V` | if `V` | `K: FromForm + Ord`, `V: FromForm` |
|
||||||
|
/// | [`Range<T>`] | _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `start`, `end` fields |
|
||||||
|
/// | [`RangeFrom<T>`] | _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `start` field |
|
||||||
|
/// | [`RangeTo<T>`] | _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `end` field |
|
||||||
|
/// | [`RangeToInclusive<T>`]| _inherit_ | **no default** | if `T` | if `T` | `T: FromForm`, expects `end` field |
|
||||||
/// | `bool` | _inherit_ | `false` | No | Yes | `"yes"/"on"/"true"`, `"no"/"off"/"false"` |
|
/// | `bool` | _inherit_ | `false` | No | Yes | `"yes"/"on"/"true"`, `"no"/"off"/"false"` |
|
||||||
/// | (un)signed int | _inherit_ | **no default** | No | Yes | `{u,i}{size,8,16,32,64,128}` |
|
/// | (un)signed int | _inherit_ | **no default** | No | Yes | `{u,i}{size,8,16,32,64,128}` |
|
||||||
/// | _nonzero_ int | _inherit_ | **no default** | No | Yes | `NonZero{I,U}{size,8,16,32,64,128}` |
|
/// | _nonzero_ int | _inherit_ | **no default** | No | Yes | `NonZero{I,U}{size,8,16,32,64,128}` |
|
||||||
|
@ -140,6 +144,10 @@ use crate::http::uncased::AsUncased;
|
||||||
/// [`SocketAddr`]: std::net::SocketAddr
|
/// [`SocketAddr`]: std::net::SocketAddr
|
||||||
/// [`SocketAddrV4`]: std::net::SocketAddrV4
|
/// [`SocketAddrV4`]: std::net::SocketAddrV4
|
||||||
/// [`SocketAddrV6`]: std::net::SocketAddrV6
|
/// [`SocketAddrV6`]: std::net::SocketAddrV6
|
||||||
|
/// [`Range<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.Range.html
|
||||||
|
/// [`RangeFrom<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.RangeFrom.html
|
||||||
|
/// [`RangeTo<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.RangeTo.html
|
||||||
|
/// [`RangeToInclusive<T>`]: https://doc.rust-lang.org/stable/std/ops/struct.RangeToInclusive.html
|
||||||
///
|
///
|
||||||
/// ## Additional Notes
|
/// ## Additional Notes
|
||||||
///
|
///
|
||||||
|
@ -931,3 +939,51 @@ impl<'v, T: FromForm<'v> + Sync> FromForm<'v> for Arc<T> {
|
||||||
T::finalize(this).map(Arc::new)
|
T::finalize(this).map(Arc::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_via_proxy {
|
||||||
|
($R:ident => struct $T:ident <$($G:ident),*> { $($f:ident : $F:ident),* }) => {
|
||||||
|
const _: () = {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
mod proxy {
|
||||||
|
#[derive(rocket::FromForm)]
|
||||||
|
pub struct $T<$($G),*> {
|
||||||
|
$(pub $f : $F),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[crate::async_trait]
|
||||||
|
impl<'v, $($G: Send),*> FromForm<'v> for $R<$($G),*>
|
||||||
|
where proxy::$T<$($G),*>: FromForm<'v>
|
||||||
|
{
|
||||||
|
type Context = <proxy::$T<$($G),*> as FromForm<'v>>::Context;
|
||||||
|
|
||||||
|
fn init(opts: Options) -> Self::Context {
|
||||||
|
<proxy::$T<$($G),*>>::init(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_value(ctxt: &mut Self::Context, field: ValueField<'v>) {
|
||||||
|
<proxy::$T<$($G),*>>::push_value(ctxt, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn push_data(ctxt: &mut Self::Context, field: DataField<'v, '_>) {
|
||||||
|
<proxy::$T<$($G),*>>::push_data(ctxt, field).await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(this: Self::Context) -> Result<'v, Self> {
|
||||||
|
let proxy = <proxy::$T<$($G),*>>::finalize(this)?;
|
||||||
|
Ok($R {
|
||||||
|
$($f : proxy.$f),*
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::ops::{Range, RangeFrom, RangeTo, RangeToInclusive};
|
||||||
|
|
||||||
|
impl_via_proxy!(Range => struct Range<T> { start: T, end: T });
|
||||||
|
impl_via_proxy!(RangeFrom => struct RangeFrom<T> { start: T });
|
||||||
|
impl_via_proxy!(RangeTo => struct RangeTo<T> { end: T });
|
||||||
|
impl_via_proxy!(RangeToInclusive => struct RangeToInclusive<T> { end: T });
|
||||||
|
|
|
@ -391,6 +391,7 @@ macro_rules! impl_with_parse {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_with_parse!(
|
impl_with_parse!(
|
||||||
|
char,
|
||||||
f32, f64,
|
f32, f64,
|
||||||
isize, i8, i16, i32, i64, i128,
|
isize, i8, i16, i32, i64, i128,
|
||||||
usize, u8, u16, u32, u64, u128,
|
usize, u8, u16, u32, u64, u128,
|
||||||
|
@ -398,7 +399,7 @@ impl_with_parse!(
|
||||||
NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
|
NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
|
||||||
Ipv4Addr, IpAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr
|
Ipv4Addr, IpAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr
|
||||||
);
|
);
|
||||||
//
|
|
||||||
// Keep formats in sync with 'FromFormField' impls.
|
// Keep formats in sync with 'FromFormField' impls.
|
||||||
static DATE_FMT: &[FormatItem<'_>] = format_description!("[year padding:none]-[month]-[day]");
|
static DATE_FMT: &[FormatItem<'_>] = format_description!("[year padding:none]-[month]-[day]");
|
||||||
static TIME_FMT1: &[FormatItem<'_>] = format_description!("[hour padding:none]:[minute]:[second]");
|
static TIME_FMT1: &[FormatItem<'_>] = format_description!("[hour padding:none]:[minute]:[second]");
|
||||||
|
|
|
@ -107,6 +107,9 @@
|
||||||
//! [testing guide]: https://rocket.rs/master/guide/testing/#testing
|
//! [testing guide]: https://rocket.rs/master/guide/testing/#testing
|
||||||
//! [Figment]: https://docs.rs/figment
|
//! [Figment]: https://docs.rs/figment
|
||||||
|
|
||||||
|
// Allows using Rocket's codegen in Rocket itself.
|
||||||
|
extern crate self as rocket;
|
||||||
|
|
||||||
/// These are public dependencies! Update docs if these are changed, especially
|
/// These are public dependencies! Update docs if these are changed, especially
|
||||||
/// figment's version number in docs.
|
/// figment's version number in docs.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -149,11 +152,12 @@ pub mod tls;
|
||||||
#[cfg_attr(nightly, doc(cfg(feature = "mtls")))]
|
#[cfg_attr(nightly, doc(cfg(feature = "mtls")))]
|
||||||
pub mod mtls;
|
pub mod mtls;
|
||||||
|
|
||||||
|
#[path = "rocket.rs"]
|
||||||
|
mod rkt;
|
||||||
mod util;
|
mod util;
|
||||||
mod server;
|
mod server;
|
||||||
mod lifecycle;
|
mod lifecycle;
|
||||||
mod state;
|
mod state;
|
||||||
mod rocket;
|
|
||||||
mod router;
|
mod router;
|
||||||
mod phase;
|
mod phase;
|
||||||
mod erased;
|
mod erased;
|
||||||
|
@ -171,7 +175,7 @@ mod erased;
|
||||||
#[doc(inline)] pub use crate::error::Error;
|
#[doc(inline)] pub use crate::error::Error;
|
||||||
#[doc(inline)] pub use crate::sentinel::Sentinel;
|
#[doc(inline)] pub use crate::sentinel::Sentinel;
|
||||||
#[doc(inline)] pub use crate::request::Request;
|
#[doc(inline)] pub use crate::request::Request;
|
||||||
#[doc(inline)] pub use crate::rocket::Rocket;
|
#[doc(inline)] pub use crate::rkt::Rocket;
|
||||||
#[doc(inline)] pub use crate::shutdown::Shutdown;
|
#[doc(inline)] pub use crate::shutdown::Shutdown;
|
||||||
#[doc(inline)] pub use crate::state::State;
|
#[doc(inline)] pub use crate::state::State;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue