mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-23 04:52:28 +00:00
add derive macro for resource
This commit is contained in:
parent
75c399d97a
commit
0cf7c9aa3a
9 changed files with 132 additions and 15 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -220,7 +220,6 @@ dependencies = [
|
||||||
"fake 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fake 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gotham 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gotham 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gotham_restful 0.0.1",
|
"gotham_restful 0.0.1",
|
||||||
"gotham_restful_derive 0.0.1",
|
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -358,6 +357,7 @@ dependencies = [
|
||||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gotham 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gotham 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gotham_derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gotham_derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"gotham_restful_derive 0.0.1",
|
||||||
"hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -17,7 +17,6 @@ gitlab = { repository = "msrd0/gotham-restful", branch = "master" }
|
||||||
fake = "2.2"
|
fake = "2.2"
|
||||||
gotham = "0.4"
|
gotham = "0.4"
|
||||||
gotham_restful = { path = "../gotham_restful", features = ["openapi"] }
|
gotham_restful = { path = "../gotham_restful", features = ["openapi"] }
|
||||||
gotham_restful_derive = { path = "../gotham_restful_derive", features = ["openapi"] }
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
log4rs = { version = "0.8", features = ["console_appender"], default-features = false }
|
log4rs = { version = "0.8", features = ["console_appender"], default-features = false }
|
||||||
serde = "1"
|
serde = "1"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate gotham_restful_derive;
|
|
||||||
|
|
||||||
use fake::{faker::internet::en::Username, Fake};
|
use fake::{faker::internet::en::Username, Fake};
|
||||||
use gotham::{
|
use gotham::{
|
||||||
|
@ -17,13 +16,19 @@ use log4rs::{
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
rest_resource!{Users, route => {
|
#[derive(Resource)]
|
||||||
route.read_all::<Self, _>();
|
#[rest_resource(ReadAll, Read, Create, DeleteAll, Delete, Update, UpdateAll)]
|
||||||
route.read::<Self, _, _>();
|
struct Users
|
||||||
route.create::<Self, _, _>();
|
{
|
||||||
route.update_all::<Self, _, _>();
|
}
|
||||||
route.update::<Self, _, _, _>();
|
|
||||||
}}
|
// rest_resource!{Users, route => {
|
||||||
|
// route.read_all::<Self, _>();
|
||||||
|
// route.read::<Self, _, _>();
|
||||||
|
// route.create::<Self, _, _>();
|
||||||
|
// route.update_all::<Self, _, _>();
|
||||||
|
// route.update::<Self, _, _, _>();
|
||||||
|
// }}
|
||||||
|
|
||||||
#[derive(Deserialize, OpenapiType, Serialize)]
|
#[derive(Deserialize, OpenapiType, Serialize)]
|
||||||
struct User
|
struct User
|
||||||
|
|
|
@ -21,6 +21,7 @@ failure = "0.1"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
gotham = "0.4"
|
gotham = "0.4"
|
||||||
gotham_derive = "0.4"
|
gotham_derive = "0.4"
|
||||||
|
gotham_restful_derive = { path = "../gotham_restful_derive" }
|
||||||
hyper = "0.12"
|
hyper = "0.12"
|
||||||
indexmap = { version = "1.0", optional = true }
|
indexmap = { version = "1.0", optional = true }
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
|
@ -30,5 +31,5 @@ serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["openapi", "chrono"]
|
default = []
|
||||||
openapi = ["indexmap", "log", "openapiv3"]
|
openapi = ["gotham_restful_derive/openapi", "indexmap", "log", "openapiv3"]
|
||||||
|
|
|
@ -4,6 +4,17 @@
|
||||||
pub use hyper::StatusCode;
|
pub use hyper::StatusCode;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
|
pub use gotham_restful_derive::*;
|
||||||
|
/// Not public API
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod export
|
||||||
|
{
|
||||||
|
#[cfg(feature = "openapi")]
|
||||||
|
pub use indexmap::IndexMap;
|
||||||
|
#[cfg(feature = "openapi")]
|
||||||
|
pub use openapiv3;
|
||||||
|
}
|
||||||
|
|
||||||
pub mod helper;
|
pub mod helper;
|
||||||
|
|
||||||
#[cfg(feature = "openapi")]
|
#[cfg(feature = "openapi")]
|
||||||
|
|
|
@ -5,8 +5,10 @@ use chrono::{
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use openapiv3::{
|
use openapiv3::{
|
||||||
ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, ReferenceOr::Reference, Schema,
|
ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, ReferenceOr::Reference, Schema,
|
||||||
SchemaData, SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty
|
SchemaData, SchemaKind, StringType, Type
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
use openapiv3::{StringFormat, VariantOrUnknownOrEmpty};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct OpenapiSchema
|
pub struct OpenapiSchema
|
||||||
|
|
|
@ -4,6 +4,8 @@ use proc_macro::TokenStream;
|
||||||
|
|
||||||
mod method;
|
mod method;
|
||||||
use method::{expand_method, Method};
|
use method::{expand_method, Method};
|
||||||
|
mod resource;
|
||||||
|
use resource::expand_resource;
|
||||||
#[cfg(feature = "openapi")]
|
#[cfg(feature = "openapi")]
|
||||||
mod openapi_type;
|
mod openapi_type;
|
||||||
|
|
||||||
|
@ -14,6 +16,12 @@ pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream
|
||||||
openapi_type::expand(tokens)
|
openapi_type::expand(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(Resource, attributes(rest_resource))]
|
||||||
|
pub fn derive_resource(tokens : TokenStream) -> TokenStream
|
||||||
|
{
|
||||||
|
expand_resource(tokens)
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn rest_read_all(attr : TokenStream, item : TokenStream) -> TokenStream
|
pub fn rest_read_all(attr : TokenStream, item : TokenStream) -> TokenStream
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,7 @@ use syn::{
|
||||||
ReturnType,
|
ReturnType,
|
||||||
parse_macro_input
|
parse_macro_input
|
||||||
};
|
};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub enum Method
|
pub enum Method
|
||||||
{
|
{
|
||||||
|
@ -19,9 +20,27 @@ pub enum Method
|
||||||
Delete
|
Delete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for Method
|
||||||
|
{
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(str : &str) -> Result<Self, Self::Err>
|
||||||
|
{
|
||||||
|
match str {
|
||||||
|
"ReadAll" | "read_all" => Ok(Self::ReadAll),
|
||||||
|
"Read" | "read" => Ok(Self::Read),
|
||||||
|
"Create" | "create" => Ok(Self::Create),
|
||||||
|
"UpdateAll" | "update_all" => Ok(Self::UpdateAll),
|
||||||
|
"Update" | "update" => Ok(Self::Update),
|
||||||
|
"DeleteAll" | "delete_all" => Ok(Self::DeleteAll),
|
||||||
|
"Delete" | "delete" => Ok(Self::Delete),
|
||||||
|
_ => Err("unknown method".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Method
|
impl Method
|
||||||
{
|
{
|
||||||
fn trait_ident(&self) -> Ident
|
pub fn trait_ident(&self) -> Ident
|
||||||
{
|
{
|
||||||
use Method::*;
|
use Method::*;
|
||||||
|
|
||||||
|
@ -37,7 +56,7 @@ impl Method
|
||||||
format_ident!("Resource{}", name)
|
format_ident!("Resource{}", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_ident(&self) -> Ident
|
pub fn fn_ident(&self) -> Ident
|
||||||
{
|
{
|
||||||
use Method::*;
|
use Method::*;
|
||||||
|
|
||||||
|
@ -52,6 +71,11 @@ impl Method
|
||||||
};
|
};
|
||||||
format_ident!("{}", name)
|
format_ident!("{}", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setup_ident(&self) -> Ident
|
||||||
|
{
|
||||||
|
format_ident!("{}_setup_impl", self.fn_ident())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
|
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
|
||||||
|
@ -87,6 +111,7 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
|
||||||
|
|
||||||
let trait_ident = method.trait_ident();
|
let trait_ident = method.trait_ident();
|
||||||
let fn_ident = method.fn_ident();
|
let fn_ident = method.fn_ident();
|
||||||
|
let setup_ident = method.setup_ident();
|
||||||
|
|
||||||
let output = quote! {
|
let output = quote! {
|
||||||
impl ::gotham_restful::#trait_ident<#(#generics),*> for #ident
|
impl ::gotham_restful::#trait_ident<#(#generics),*> for #ident
|
||||||
|
@ -98,6 +123,12 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
|
||||||
#ret_stmt
|
#ret_stmt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deny(dead_code)]
|
||||||
|
fn #setup_ident<D : ::gotham_restful::DrawResourceRoutes>(route : &mut D)
|
||||||
|
{
|
||||||
|
route.#fn_ident::<#ident, #(#generics),*>();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
output.into()
|
output.into()
|
||||||
}
|
}
|
||||||
|
|
60
gotham_restful_derive/src/resource.rs
Normal file
60
gotham_restful_derive/src/resource.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
use crate::method::Method;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{
|
||||||
|
parse::{Parse, ParseStream, Result as SynResult},
|
||||||
|
punctuated::Punctuated,
|
||||||
|
token::Comma,
|
||||||
|
Ident,
|
||||||
|
ItemStruct,
|
||||||
|
parenthesized,
|
||||||
|
parse_macro_input
|
||||||
|
};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
struct MethodList(Punctuated<Ident, Comma>);
|
||||||
|
|
||||||
|
impl Parse for MethodList
|
||||||
|
{
|
||||||
|
fn parse(input: ParseStream) -> SynResult<Self>
|
||||||
|
{
|
||||||
|
let content;
|
||||||
|
let _paren = parenthesized!(content in input);
|
||||||
|
let list : Punctuated<Ident, Comma> = Punctuated::parse_separated_nonempty(&content)?;
|
||||||
|
Ok(Self(list))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_resource(tokens : TokenStream) -> TokenStream
|
||||||
|
{
|
||||||
|
let input = parse_macro_input!(tokens as ItemStruct);
|
||||||
|
let ident = input.ident;
|
||||||
|
|
||||||
|
let methods : Vec<TokenStream2> = input.attrs.into_iter().filter(|attr|
|
||||||
|
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("rest_resource".to_string()) // TODO wtf
|
||||||
|
).flat_map(|attr| {
|
||||||
|
let m : MethodList = syn::parse2(attr.tokens).expect("unable to parse attributes");
|
||||||
|
m.0.into_iter()
|
||||||
|
}).map(|method| {
|
||||||
|
let method = Method::from_str(&method.to_string()).expect("unknown method");
|
||||||
|
let ident = method.setup_ident();
|
||||||
|
quote!(#ident(&mut route);)
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let output = quote! {
|
||||||
|
impl ::gotham_restful::Resource for #ident
|
||||||
|
{
|
||||||
|
fn name() -> String
|
||||||
|
{
|
||||||
|
stringify!(#ident).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup<D : ::gotham_restful::DrawResourceRoutes>(mut route : D)
|
||||||
|
{
|
||||||
|
#(#methods)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
output.into()
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue