2020-04-15 21:41:24 +02:00
|
|
|
use crate::{
|
|
|
|
method::Method,
|
|
|
|
util::CollectToResult
|
|
|
|
};
|
2019-10-06 15:03:30 +02:00
|
|
|
use proc_macro::TokenStream;
|
|
|
|
use proc_macro2::TokenStream as TokenStream2;
|
|
|
|
use quote::quote;
|
|
|
|
use syn::{
|
2020-04-15 21:41:24 +02:00
|
|
|
parse::{Parse, ParseStream},
|
2019-10-06 15:03:30 +02:00
|
|
|
punctuated::Punctuated,
|
|
|
|
token::Comma,
|
2020-05-03 23:10:19 +02:00
|
|
|
DeriveInput,
|
2020-04-15 21:41:24 +02:00
|
|
|
Error,
|
2019-10-06 15:03:30 +02:00
|
|
|
Ident,
|
|
|
|
parenthesized,
|
|
|
|
parse_macro_input
|
|
|
|
};
|
2020-04-15 21:41:24 +02:00
|
|
|
use std::{iter, str::FromStr};
|
2019-10-06 15:03:30 +02:00
|
|
|
|
|
|
|
struct MethodList(Punctuated<Ident, Comma>);
|
|
|
|
|
|
|
|
impl Parse for MethodList
|
|
|
|
{
|
2020-04-15 21:41:24 +02:00
|
|
|
fn parse(input: ParseStream) -> Result<Self, Error>
|
2019-10-06 15:03:30 +02:00
|
|
|
{
|
|
|
|
let content;
|
|
|
|
let _paren = parenthesized!(content in input);
|
|
|
|
let list : Punctuated<Ident, Comma> = Punctuated::parse_separated_nonempty(&content)?;
|
|
|
|
Ok(Self(list))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-15 21:41:24 +02:00
|
|
|
fn expand(tokens : TokenStream) -> Result<TokenStream2, Error>
|
2019-10-06 15:03:30 +02:00
|
|
|
{
|
2019-10-14 02:17:25 +02:00
|
|
|
let krate = super::krate();
|
2020-05-03 23:10:19 +02:00
|
|
|
let input = parse_macro_input::parse::<DeriveInput>(tokens)?;
|
2019-10-06 15:03:30 +02:00
|
|
|
let ident = input.ident;
|
2020-04-07 20:44:02 +00:00
|
|
|
let name = ident.to_string();
|
2019-10-06 15:03:30 +02:00
|
|
|
|
2020-04-15 21:41:24 +02:00
|
|
|
let methods = input.attrs.into_iter().filter(|attr|
|
2019-10-06 15:03:30 +02:00
|
|
|
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("rest_resource".to_string()) // TODO wtf
|
2020-04-15 21:41:24 +02:00
|
|
|
).map(|attr| {
|
|
|
|
syn::parse2(attr.tokens).map(|m : MethodList| m.0.into_iter())
|
|
|
|
}).flat_map(|list| match list {
|
|
|
|
Ok(iter) => Box::new(iter.map(|method| {
|
|
|
|
let method = Method::from_str(&method.to_string()).map_err(|err| Error::new(method.span(), err))?;
|
|
|
|
let mod_ident = method.mod_ident(&name);
|
|
|
|
let ident = method.setup_ident(&name);
|
|
|
|
Ok(quote!(#mod_ident::#ident(&mut route);))
|
|
|
|
})) as Box<dyn Iterator<Item = Result<TokenStream2, Error>>>,
|
|
|
|
Err(err) => Box::new(iter::once(Err(err)))
|
|
|
|
}).collect_to_result()?;
|
2019-10-06 15:03:30 +02:00
|
|
|
|
2020-04-15 21:41:24 +02:00
|
|
|
Ok(quote! {
|
2019-10-14 02:17:25 +02:00
|
|
|
impl #krate::Resource for #ident
|
2019-10-06 15:03:30 +02:00
|
|
|
{
|
|
|
|
fn name() -> String
|
|
|
|
{
|
|
|
|
stringify!(#ident).to_string()
|
|
|
|
}
|
|
|
|
|
2019-10-14 02:17:25 +02:00
|
|
|
fn setup<D : #krate::DrawResourceRoutes>(mut route : D)
|
2019-10-06 15:03:30 +02:00
|
|
|
{
|
|
|
|
#(#methods)*
|
|
|
|
}
|
|
|
|
}
|
2020-04-15 21:41:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand_resource(tokens : TokenStream) -> TokenStream
|
|
|
|
{
|
|
|
|
expand(tokens)
|
|
|
|
.unwrap_or_else(|err| err.to_compile_error())
|
|
|
|
.into()
|
2019-10-06 15:03:30 +02:00
|
|
|
}
|