mirror of https://github.com/rwf2/Rocket.git
Add derive for 'UriDisplay'.
This commit is contained in:
parent
34421f13f3
commit
cda4c520f1
|
@ -1,3 +1,4 @@
|
|||
pub mod from_form;
|
||||
pub mod from_form_value;
|
||||
pub mod responder;
|
||||
pub mod uri_display;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
use proc_macro::{Span, TokenStream};
|
||||
use derive_utils::*;
|
||||
|
||||
const NO_EMPTY_FIELDS: &str = "fieldless structs or variants are not allowed";
|
||||
const NO_NULLARY: &str = "nullary items are not allowed";
|
||||
const NO_EMPTY_ENUMS: &str = "empty enums are not allowed";
|
||||
const ONLY_ONE_UNNAMED: &str = "tuple structs or variants must have exactly one field";
|
||||
|
||||
fn validate_fields(fields: Fields, parent_span: Span) -> Result<()> {
|
||||
if fields.count() == 0 {
|
||||
return Err(parent_span.error(NO_EMPTY_FIELDS))
|
||||
} else if fields.are_unnamed() && fields.count() > 1 {
|
||||
return Err(fields.span().error(ONLY_ONE_UNNAMED));
|
||||
} else if fields.are_unit() {
|
||||
return Err(parent_span.error(NO_NULLARY));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_struct(gen: &DeriveGenerator, data: Struct) -> Result<()> {
|
||||
validate_fields(data.fields(), gen.input.span())
|
||||
}
|
||||
|
||||
fn validate_enum(gen: &DeriveGenerator, data: Enum) -> Result<()> {
|
||||
if data.variants().count() == 0 {
|
||||
return Err(gen.input.span().error(NO_EMPTY_ENUMS));
|
||||
}
|
||||
|
||||
for variant in data.variants() {
|
||||
validate_fields(variant.fields(), variant.span())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn derive_uri_display(input: TokenStream) -> TokenStream {
|
||||
DeriveGenerator::build_for(input, "::rocket::http::uri::UriDisplay")
|
||||
.generic_support(GenericSupport::Type | GenericSupport::Lifetime)
|
||||
.data_support(DataSupport::Struct | DataSupport::Enum)
|
||||
.validate_enum(validate_enum)
|
||||
.validate_struct(validate_struct)
|
||||
.map_type_generic(|_, ident, _| quote!(#ident : ::rocket::http::uri::UriDisplay))
|
||||
.function(|_, inner| quote! {
|
||||
fn fmt(&self, f: &mut ::rocket::http::uri::Formatter) -> ::std::fmt::Result {
|
||||
#inner
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.map_field(|_, field| {
|
||||
let span = field.span().into();
|
||||
let accessor = field.accessor();
|
||||
if let Some(ref ident) = field.ident {
|
||||
let name = ident.to_string();
|
||||
quote_spanned!(span => f.write_named_value(#name, &#accessor)?;)
|
||||
} else {
|
||||
quote_spanned!(span => f.write_value(&#accessor)?;)
|
||||
}
|
||||
})
|
||||
.to_tokens()
|
||||
}
|
|
@ -583,6 +583,11 @@ pub fn derive_responder(input: TokenStream) -> TokenStream {
|
|||
emit!(derive::responder::derive_responder(input))
|
||||
}
|
||||
|
||||
#[proc_macro_derive(UriDisplay)]
|
||||
pub fn derive_uri_display(input: TokenStream) -> TokenStream {
|
||||
emit!(derive::uri_display::derive_uri_display(input))
|
||||
}
|
||||
|
||||
/// Generates a [`Vec`] of [`Route`]s from a set of route paths.
|
||||
///
|
||||
/// The `routes!` macro expands a list of route paths into a [`Vec`] of their
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rocket::{Request, Outcome::*};
|
||||
|
@ -10,22 +9,15 @@ use rocket::http::ext::Normalize;
|
|||
use rocket::local::Client;
|
||||
use rocket::data::{self, Data, FromDataSimple};
|
||||
use rocket::request::Form;
|
||||
use rocket::http::{Status, RawStr, ContentType, uri::{Formatter, UriDisplay}};
|
||||
use rocket::http::{Status, RawStr, ContentType};
|
||||
|
||||
// Use all of the code generation avaiable at once.
|
||||
|
||||
#[derive(FromForm)]
|
||||
#[derive(FromForm, UriDisplay)]
|
||||
struct Inner<'r> {
|
||||
field: &'r RawStr
|
||||
}
|
||||
|
||||
// TODO: Make this deriveable.
|
||||
impl<'a> UriDisplay for Inner<'a> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
f.write_named_value("field", &self.field)
|
||||
}
|
||||
}
|
||||
|
||||
struct Simple(String);
|
||||
|
||||
impl FromDataSimple for Simple {
|
||||
|
|
|
@ -3,27 +3,18 @@
|
|||
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rocket::http::{RawStr, Cookies};
|
||||
use rocket::http::uri::{Origin, Formatter, UriDisplay, FromUriParam};
|
||||
use rocket::http::uri::{Origin, FromUriParam};
|
||||
use rocket::request::Form;
|
||||
|
||||
#[derive(FromForm)]
|
||||
#[derive(FromForm, UriDisplay)]
|
||||
struct User<'a> {
|
||||
name: &'a RawStr,
|
||||
nickname: String,
|
||||
}
|
||||
|
||||
// TODO: Make this deriveable.
|
||||
impl<'a> UriDisplay for User<'a> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
f.write_named_value("name", &self.name)?;
|
||||
f.write_named_value("nickname", &self.nickname)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> FromUriParam<(&'a str, &'b str)> for User<'a> {
|
||||
type Target = User<'a>;
|
||||
fn from_uri_param((name, nickname): (&'a str, &'b str)) -> User<'a> {
|
||||
|
|
Loading…
Reference in New Issue