Skip to content

Commit

Permalink
wip: fromform range impl
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioBenitez committed May 2, 2024
1 parent a811a18 commit 609a412
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 3 deletions.
8 changes: 8 additions & 0 deletions core/codegen/src/derive/form_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ use quote::{ToTokens, TokenStreamExt};
use crate::syn_ext::IdentExt;
use crate::name::Name;

macro_rules! quote_spanned {
($span:expr => $($token:tt)*) => (
quote::quote_spanned!(
proc_macro2::Span::call_site().located_at($span) => $($token)*
)
)
}

#[derive(Debug)]
pub enum FieldName {
Cased(Name),
Expand Down
8 changes: 8 additions & 0 deletions core/codegen/src/derive/from_form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ use crate::syn_ext::{GenericsExt as _, TypeExt as _};

type WherePredicates = syn::punctuated::Punctuated<syn::WherePredicate, syn::Token![,]>;

macro_rules! quote_spanned {
($span:expr => $($token:tt)*) => (
quote::quote_spanned!(
proc_macro2::Span::call_site().located_at($span) => $($token)*
)
)
}

// F: fn(field_ty: Ty, field_context: Expr)
fn fields_map<F>(fields: Fields<'_>, map_f: F) -> Result<TokenStream>
where F: Fn(&syn::Type, &syn::Expr) -> TokenStream
Expand Down
47 changes: 47 additions & 0 deletions core/codegen/tests/from_form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -991,3 +991,50 @@ struct Q<T>(T);
// This is here to ensure we don't warn, which we can't test with trybuild.
#[derive(FromForm)]
pub struct JsonTokenBad<T>(Q<T>);

#[test]
fn range() {
use std::ops::{Range, RangeFrom, RangeTo, RangeToInclusive};

let range: Range<usize> = strict("start=1&end=2").unwrap();
assert_eq!(range, Range { start: 1, end: 2 });

let range: Range<isize> = strict_encoded("start=-1&end=2").unwrap();
assert_eq!(range, Range { start: -1, end: 2 });

let range: Range<isize> = strict("start=-1&end=-95").unwrap();
assert_eq!(range, Range { start: -1, end: -95 });

let range: Range<isize> = strict_encoded("start=-1&end=-95").unwrap();
assert_eq!(range, Range { start: -1, end: -95 });

let range: RangeFrom<char> = strict("start=a").unwrap();
assert_eq!(range, RangeFrom { start: 'a' });

let range: RangeTo<char> = strict("end=z").unwrap();
assert_eq!(range, RangeTo { end: 'z' });

let range: RangeToInclusive<u8> = strict("end=255").unwrap();
assert_eq!(range, RangeToInclusive { end: 255 });

// now with compound, non-Step values
let form_string = &["start.start=0", "start.end=1", "end.start=1", "end.end=2"].join("&");
let range: Range<Range<usize>> = strict(&form_string).unwrap();
assert_eq!(range, Range {
start: Range { start: 0, end : 1},
end: Range { start: 1, end : 2 }
});

let form_string = &[
"start.description=some%20task",
"start.completed=false",
"end.description=yet%20more%20work",
"end.completed=true",
].join("&");

let range: Range<TodoTask> = strict_encoded(form_string).unwrap();
assert_eq!(range, Range {
start: TodoTask { description: "some task".into(), completed: false, },
end: TodoTask { description: "yet more work".into(), completed: true, },
});
}
7 changes: 7 additions & 0 deletions core/lib/src/form/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use std::{fmt, io};
use std::num::{ParseIntError, ParseFloatError};
use std::str::{Utf8Error, ParseBoolError};
use std::char::ParseCharError;
use std::net::AddrParseError;
use std::borrow::Cow;

Expand Down Expand Up @@ -200,6 +201,8 @@ pub enum ErrorKind<'v> {
Multipart(multer::Error),
/// A string was invalid UTF-8.
Utf8(Utf8Error),
/// A value failed to parse as a char.
Char(ParseCharError),
/// A value failed to parse as an integer.
Int(ParseIntError),
/// A value failed to parse as a boolean.
Expand Down Expand Up @@ -857,6 +860,7 @@ impl fmt::Display for ErrorKind<'_> {
ErrorKind::Custom(_, e) => e.fmt(f)?,
ErrorKind::Multipart(e) => write!(f, "invalid multipart: {}", 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::Bool(e) => write!(f, "invalid boolean: {}", e)?,
ErrorKind::Float(e) => write!(f, "invalid float: {}", e)?,
Expand Down Expand Up @@ -885,6 +889,7 @@ impl crate::http::ext::IntoOwned for ErrorKind<'_> {
Custom(s, e) => Custom(s, e),
Multipart(e) => Multipart(e),
Utf8(e) => Utf8(e),
Char(e) => Char(e),
Int(e) => Int(e),
Bool(e) => Bool(e),
Float(e) => Float(e),
Expand Down Expand Up @@ -985,6 +990,7 @@ macro_rules! impl_from_for {

impl_from_for!(<'a> Utf8Error => ErrorKind<'a> as Utf8);
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> ParseBoolError => ErrorKind<'a> as Bool);
impl_from_for!(<'a> AddrParseError => ErrorKind<'a> as Addr);
Expand Down Expand Up @@ -1024,6 +1030,7 @@ impl Entity {
| ErrorKind::OutOfRange { .. }
| ErrorKind::Validation { .. }
| ErrorKind::Utf8(_)
| ErrorKind::Char(_)
| ErrorKind::Int(_)
| ErrorKind::Float(_)
| ErrorKind::Bool(_)
Expand Down
48 changes: 48 additions & 0 deletions core/lib/src/form/from_form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,3 +931,51 @@ impl<'v, T: FromForm<'v> + Sync> FromForm<'v> for Arc<T> {
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 });
3 changes: 2 additions & 1 deletion core/lib/src/form/from_form_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,14 +391,15 @@ macro_rules! impl_with_parse {
}

impl_with_parse!(
char,
f32, f64,
isize, i8, i16, i32, i64, i128,
usize, u8, u16, u32, u64, u128,
NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
Ipv4Addr, IpAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr
);
//

// Keep formats in sync with 'FromFormField' impls.
static DATE_FMT: &[FormatItem<'_>] = format_description!("[year padding:none]-[month]-[day]");
static TIME_FMT1: &[FormatItem<'_>] = format_description!("[hour padding:none]:[minute]:[second]");
Expand Down
8 changes: 6 additions & 2 deletions core/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@
//! [testing guide]: https://rocket.rs/master/guide/testing/#testing
//! [Figment]: https://docs.rs/figment
extern crate self as rocket;

/// These are public dependencies! Update docs if these are changed, especially
/// figment's version number in docs.
#[doc(hidden)]
Expand Down Expand Up @@ -153,11 +155,13 @@ mod util;
mod server;
mod lifecycle;
mod state;
mod rocket;
mod router;
mod phase;
mod erased;

#[path = "rocket.rs"]
mod rkt;

#[doc(hidden)] pub use either::Either;

#[doc(inline)] pub use rocket_codegen::*;
Expand All @@ -171,7 +175,7 @@ mod erased;
#[doc(inline)] pub use crate::error::Error;
#[doc(inline)] pub use crate::sentinel::Sentinel;
#[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::state::State;

Expand Down

0 comments on commit 609a412

Please sign in to comment.