1 #![feature(proc_macro_diagnostic)]
2
3 #[macro_use] extern crate quote;
4 extern crate devise;
5 extern crate proc_macro;
6
7 use proc_macro::{TokenStream, Span};
8 use devise::*;
9
10 const NO_EMPTY_FIELDS: &str = "fieldless structs or variants are not allowed";
11 const NO_NULLARY: &str = "nullary items are not allowed";
12 const NO_EMPTY_ENUMS: &str = "empty enums are not allowed";
13 const ONLY_ONE_UNNAMED: &str = "tuple structs or variants must have exactly one field";
14
validate_fields(fields: Fields, parent_span: Span) -> Result<()>15 fn validate_fields(fields: Fields, parent_span: Span) -> Result<()> {
16 if fields.count() == 0 {
17 return Err(parent_span.error(NO_EMPTY_FIELDS))
18 } else if fields.are_unnamed() && fields.count() > 1 {
19 return Err(fields.span().error(ONLY_ONE_UNNAMED));
20 } else if fields.are_unit() {
21 return Err(parent_span.error(NO_NULLARY));
22 }
23
24 Ok(())
25 }
26
validate_struct(gen: &DeriveGenerator, data: Struct) -> Result<()>27 fn validate_struct(gen: &DeriveGenerator, data: Struct) -> Result<()> {
28 validate_fields(data.fields(), gen.input.span())
29 }
30
validate_enum(gen: &DeriveGenerator, data: Enum) -> Result<()>31 fn validate_enum(gen: &DeriveGenerator, data: Enum) -> Result<()> {
32 if data.variants().count() == 0 {
33 return Err(gen.input.span().error(NO_EMPTY_ENUMS));
34 }
35
36 for variant in data.variants() {
37 validate_fields(variant.fields(), variant.span())?;
38 }
39
40 Ok(())
41 }
42
43 #[proc_macro_derive(UriDisplay)]
derive_uri_display(input: TokenStream) -> TokenStream44 pub fn derive_uri_display(input: TokenStream) -> TokenStream {
45 // DeriveGenerator::build_for(input, "::rocket::uri::UriDisplay")
46 DeriveGenerator::build_for(input, quote!(impl UriDisplay))
47 .generic_support(GenericSupport::Type | GenericSupport::Lifetime)
48 .data_support(DataSupport::Struct | DataSupport::Enum)
49 .validate_enum(validate_enum)
50 .validate_struct(validate_struct)
51 // .map_type_generic(|_, ident, _| quote!(#ident : ::rocket::uri::UriDisplay))
52 .map_type_generic(|_, ident, _| quote!(#ident : UriDisplay))
53 .function(|_, inner| quote! {
54 // fn fmt(&self, f: &mut ::rocket::uri::Formatter) -> ::std::fmt::Result {
55 fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
56 #inner
57 Ok(())
58 }
59 })
60 .map_field(|_, field| {
61 let span = field.span().into();
62 let accessor = field.accessor();
63 if let Some(ref ident) = field.ident {
64 let name = ident.to_string();
65 quote_spanned!(span => f.write_named_value(#name, &#accessor)?;)
66 } else {
67 quote_spanned!(span => f.write_value(&#accessor)?;)
68 }
69 })
70 .to_tokens()
71 }
72