From 68bb3d9620b15c4f49692909d56c0e5e1dfa1693 Mon Sep 17 00:00:00 2001 From: Rasmus Hald Nielsen Date: Thu, 7 Dec 2023 17:29:54 +0100 Subject: [PATCH] Endpoint macro that auto add functions IT IS NOT DONE YET. The macro needs to add the generated code to the implementation. --- Cargo.toml | 1 + ecdar_api_macros/Cargo.toml | 14 +++++ ecdar_api_macros/src/lib.rs | 114 ++++++++++++++++++++++++++++++++++++ src/api/ecdar_api.rs | 14 +++-- src/api/mod.rs | 1 + 5 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 ecdar_api_macros/Cargo.toml create mode 100644 ecdar_api_macros/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 3881ade..194db29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ regex = "1.10.2" mockall = "0.11.4" bcrypt = "0.15.0" serde_json = "1.0.108" +ecdar_api_macros = { version = "0.1.0", path = "ecdar_api_macros" } [build-dependencies] tonic-build = "0.10.2" diff --git a/ecdar_api_macros/Cargo.toml b/ecdar_api_macros/Cargo.toml new file mode 100644 index 0000000..9ab8460 --- /dev/null +++ b/ecdar_api_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ecdar_api_macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +syn = { version = "2.0", features = ["full"] } +quote = "1.0" +# proc-macro2 = "1.0.70" diff --git a/ecdar_api_macros/src/lib.rs b/ecdar_api_macros/src/lib.rs new file mode 100644 index 0000000..221894a --- /dev/null +++ b/ecdar_api_macros/src/lib.rs @@ -0,0 +1,114 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, ImplItemFn, Item, ItemFn, ItemImpl, ItemMod}; + +#[proc_macro_attribute] +pub fn endpoints(_attr: TokenStream, item: TokenStream) -> TokenStream { + let item_mod: ItemMod = parse_macro_input!(item as ItemMod); + + let impl_names: Vec = item_mod + .clone() + .content + .as_ref() + .map(|(_, items)| { + items.iter().filter_map(|item| { + if let syn::Item::Impl(impl_item) = item { + Some( + impl_item + .trait_ + .as_ref() + .map_or_else( + || None, + |t| Some(t.1.segments.last().unwrap().ident.to_string()), + ) + .unwrap_or_else(|| "".to_string()), + ) + } else { + None + } + }) + }) + .unwrap() + .collect(); + + let names: Vec = impl_names + .clone() + .into_iter() + .filter(|item| !item.is_empty()) + .collect(); + + let mut endpoints: Vec = Vec::new(); + + let items_impl: Vec = item_mod.content.unwrap().1; + + let items_impl: Vec = items_impl + .into_iter() + .filter_map(|item| match item { + Item::Impl(item_impl) => Some(item_impl), + _ => None, + }) + .collect(); + + let items_impl: Vec = items_impl + .clone() + .into_iter() + .filter(|item| item.trait_.is_some()) + .collect(); + + for i in 0..items_impl.len() { + let existing_functions: Vec = items_impl[i] + .items + .iter() + .filter_map(|item| match item { + syn::ImplItem::Fn(function) => Some(function.sig.ident.to_string()), + _ => None, + }) + .collect(); + + for function in existing_functions { + endpoints.push(format!("{}/{}", names[i], function)); + } + } + + let new_function: TokenStream = quote! { + async fn endpoints(&self, request: tonic::Request<()>) -> std::result::Result, tonic::Status> { + let names = vec![#(#endpoints.to_string()),*]; + Ok(Response::new(EndpointsResponse { + endpoints: names + })) + } + } + .into(); + + println!("{}", new_function.to_string()); + + // let mut updated_items = item_mod.content.as_ref() + + // let mut updated_items = input.items.clone(); + + // updated_items.push(syn::ImplItem::Fn(parse_macro_input!( + // new_function as ImplItemFn + // ))); + + // let updated_impl = ItemImpl { + // attrs: input.attrs, + // defaultness: input.defaultness, + // unsafety: input.unsafety, + // impl_token: input.impl_token, + // generics: input.generics, + // trait_: input.trait_, + // self_ty: input.self_ty, + // brace_token: input.brace_token, + // items: updated_items, + // }; + + // let output = quote! { + // #updated_impl + // }; + + // println!("{}", output.to_string()); + + // output.into() + todo!() +} + diff --git a/src/api/ecdar_api.rs b/src/api/ecdar_api.rs index 85a02e5..979158f 100644 --- a/src/api/ecdar_api.rs +++ b/src/api/ecdar_api.rs @@ -1,3 +1,6 @@ +#![ecdar_api_macros::endpoints] +#![feature(custom_inner_attributes)] + use super::server::server::{ ecdar_api_auth_server::EcdarApiAuth, ecdar_api_server::EcdarApi, @@ -5,11 +8,11 @@ use super::server::server::{ get_auth_token_request::{user_credentials, UserCredentials}, CreateAccessRequest, CreateProjectRequest, CreateProjectResponse, CreateQueryRequest, CreateUserRequest, DeleteAccessRequest, DeleteProjectRequest, DeleteQueryRequest, - GetAuthTokenRequest, GetAuthTokenResponse, GetProjectRequest, GetProjectResponse, - ListProjectsInfoResponse, Query, QueryRequest, QueryResponse, SendQueryRequest, - SendQueryResponse, SimulationStartRequest, SimulationStepRequest, SimulationStepResponse, - UpdateAccessRequest, UpdateProjectRequest, UpdateQueryRequest, UpdateUserRequest, - UserTokenResponse, + EndpointsResponse, GetAuthTokenRequest, GetAuthTokenResponse, GetProjectRequest, + GetProjectResponse, ListProjectsInfoResponse, Query, QueryRequest, QueryResponse, + SendQueryRequest, SendQueryResponse, SimulationStartRequest, SimulationStepRequest, + SimulationStepResponse, UpdateAccessRequest, UpdateProjectRequest, UpdateQueryRequest, + UpdateUserRequest, UserTokenResponse, }; use crate::api::context_collection::ContextCollection; use crate::api::{ @@ -1050,3 +1053,4 @@ mod user_logic_tests; #[cfg(test)] #[path = "../tests/api/session_logic.rs"] mod session_logic_tests; + diff --git a/src/api/mod.rs b/src/api/mod.rs index 3e8aa2c..199708c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -4,3 +4,4 @@ pub mod ecdar_api; pub mod hashing_context; pub mod reveaal_context; pub mod server; +