mirror of
https://github.com/Start9Labs/rpc-toolkit.git
synced 2026-03-30 20:24:48 +00:00
macros wip
This commit is contained in:
@@ -11,3 +11,4 @@ license = "MIT"
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0", features = ["full", "fold"] }
|
||||
itertools = "0.12"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ impl Default for ExecutionContext {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LeafOptions {
|
||||
macro_debug: bool,
|
||||
macro_debug: Option<Path>,
|
||||
blocking: Option<Path>,
|
||||
is_async: bool,
|
||||
aliases: Vec<LitStr>,
|
||||
@@ -34,6 +34,7 @@ pub struct LeafOptions {
|
||||
exec_ctx: ExecutionContext,
|
||||
display: Option<Path>,
|
||||
metadata: HashMap<Ident, Lit>,
|
||||
clap_attr: Vec<NestedMeta>,
|
||||
}
|
||||
|
||||
pub struct SelfImplInfo {
|
||||
@@ -79,22 +80,18 @@ impl Options {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ArgOptions {
|
||||
ty: Type,
|
||||
optional: bool,
|
||||
check_is_present: bool,
|
||||
help: Option<LitStr>,
|
||||
name: Option<Ident>,
|
||||
rename: Option<LitStr>,
|
||||
short: Option<LitChar>,
|
||||
long: Option<LitStr>,
|
||||
parse: Option<Path>,
|
||||
default: Option<Option<LitStr>>,
|
||||
count: Option<Path>,
|
||||
multiple: Option<Path>,
|
||||
stdin: Option<Path>,
|
||||
default: Option<Path>,
|
||||
clap_attr: Vec<NestedMeta>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ParamType {
|
||||
None,
|
||||
Arg(ArgOptions),
|
||||
|
||||
@@ -7,7 +7,7 @@ pub fn parse_command_attr(args: AttributeArgs) -> Result<Options> {
|
||||
for arg in args {
|
||||
match arg {
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("macro_debug") => {
|
||||
opt.common().macro_debug = true;
|
||||
opt.common().macro_debug = Some(p);
|
||||
}
|
||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("subcommands") => {
|
||||
let inner = opt.to_parent()?;
|
||||
@@ -536,25 +536,20 @@ pub fn parse_command_attr(args: AttributeArgs) -> Result<Options> {
|
||||
|
||||
pub fn parse_arg_attr(attr: Attribute, arg: PatType) -> Result<ArgOptions> {
|
||||
let arg_span = arg.span();
|
||||
let meta = attr.parse_meta()?;
|
||||
let mut opt = ArgOptions {
|
||||
ty: *arg.ty,
|
||||
optional: false,
|
||||
check_is_present: false,
|
||||
help: None,
|
||||
name: match *arg.pat {
|
||||
Pat::Ident(i) => Some(i.ident),
|
||||
_ => None,
|
||||
},
|
||||
rename: None,
|
||||
short: None,
|
||||
long: None,
|
||||
parse: None,
|
||||
default: None,
|
||||
count: None,
|
||||
multiple: None,
|
||||
stdin: None,
|
||||
default: None,
|
||||
clap_attr: Vec::new(),
|
||||
};
|
||||
match attr.parse_meta()? {
|
||||
match meta {
|
||||
Meta::List(list) => {
|
||||
for arg in list.nested {
|
||||
match arg {
|
||||
@@ -591,34 +586,10 @@ pub fn parse_arg_attr(attr: Attribute, arg: PatType) -> Result<ArgOptions> {
|
||||
return Err(Error::new(nv.path.span(), "`parse` cannot be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("stdin") => {
|
||||
if opt.short.is_some() {
|
||||
if !opt.clap_attr.is_empty() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`stdin` and `short` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
if opt.long.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`stdin` and `long` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
if opt.help.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`stdin` and `help` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
if opt.count.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`stdin` and `count` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
if opt.multiple.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`stdin` and `multiple` are mutually exclusive",
|
||||
"`stdin` and clap parser attributes are mutually exclusive",
|
||||
));
|
||||
}
|
||||
opt.stdin = Some(p);
|
||||
@@ -632,79 +603,6 @@ pub fn parse_arg_attr(attr: Attribute, arg: PatType) -> Result<ArgOptions> {
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("stdin") => {
|
||||
return Err(Error::new(nv.path.span(), "`stdin` cannot be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("count") => {
|
||||
if opt.stdin.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`stdin` and `count` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
if opt.multiple.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`count` and `multiple` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
opt.count = Some(p);
|
||||
}
|
||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("count") => {
|
||||
return Err(Error::new(
|
||||
list.path.span(),
|
||||
"`count` does not take any arguments",
|
||||
));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("count") => {
|
||||
return Err(Error::new(nv.path.span(), "`count` cannot be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("multiple") => {
|
||||
if opt.stdin.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`stdin` and `multiple` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
if opt.count.is_some() {
|
||||
return Err(Error::new(
|
||||
p.span(),
|
||||
"`count` and `multiple` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
opt.multiple = Some(p);
|
||||
}
|
||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("multiple") => {
|
||||
return Err(Error::new(
|
||||
list.path.span(),
|
||||
"`multiple` does not take any arguments",
|
||||
));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("count") => {
|
||||
return Err(Error::new(nv.path.span(), "`count` cannot be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("help") => {
|
||||
if let Lit::Str(help) = nv.lit {
|
||||
if opt.help.is_some() {
|
||||
return Err(Error::new(help.span(), "duplicate argument `help`"));
|
||||
}
|
||||
if opt.stdin.is_some() {
|
||||
return Err(Error::new(
|
||||
help.span(),
|
||||
"`stdin` and `help` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
opt.help = Some(help);
|
||||
} else {
|
||||
return Err(Error::new(nv.lit.span(), "help message must be a string"));
|
||||
}
|
||||
}
|
||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("help") => {
|
||||
return Err(Error::new(
|
||||
list.path.span(),
|
||||
"`help` does not take any arguments",
|
||||
));
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("help") => {
|
||||
return Err(Error::new(p.span(), "`help` must be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("rename") => {
|
||||
if let Lit::Str(rename) = nv.lit {
|
||||
if opt.rename.is_some() {
|
||||
@@ -713,6 +611,12 @@ pub fn parse_arg_attr(attr: Attribute, arg: PatType) -> Result<ArgOptions> {
|
||||
"duplicate argument `rename`",
|
||||
));
|
||||
}
|
||||
opt.clap_attr
|
||||
.push(NestedMeta::Meta(Meta::NameValue(MetaNameValue {
|
||||
path: Path::from(Ident::new("name", nv.path.span())),
|
||||
eq_token: nv.eq_token,
|
||||
lit: Lit::Str(rename.clone()),
|
||||
})));
|
||||
opt.rename = Some(rename);
|
||||
} else {
|
||||
return Err(Error::new(nv.lit.span(), "`rename` must be a string"));
|
||||
@@ -727,68 +631,8 @@ pub fn parse_arg_attr(attr: Attribute, arg: PatType) -> Result<ArgOptions> {
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("rename") => {
|
||||
return Err(Error::new(p.span(), "`rename` must be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("short") => {
|
||||
if let Lit::Char(short) = nv.lit {
|
||||
if opt.short.is_some() {
|
||||
return Err(Error::new(short.span(), "duplicate argument `short`"));
|
||||
}
|
||||
if opt.stdin.is_some() {
|
||||
return Err(Error::new(
|
||||
short.span(),
|
||||
"`stdin` and `short` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
opt.short = Some(short);
|
||||
} else {
|
||||
return Err(Error::new(nv.lit.span(), "`short` must be a char"));
|
||||
}
|
||||
}
|
||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("short") => {
|
||||
return Err(Error::new(
|
||||
list.path.span(),
|
||||
"`short` does not take any arguments",
|
||||
));
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("short") => {
|
||||
return Err(Error::new(p.span(), "`short` must be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("long") => {
|
||||
if let Lit::Str(long) = nv.lit {
|
||||
if opt.long.is_some() {
|
||||
return Err(Error::new(long.span(), "duplicate argument `long`"));
|
||||
}
|
||||
if opt.stdin.is_some() {
|
||||
return Err(Error::new(
|
||||
long.span(),
|
||||
"`stdin` and `long` are mutually exclusive",
|
||||
));
|
||||
}
|
||||
opt.long = Some(long);
|
||||
} else {
|
||||
return Err(Error::new(nv.lit.span(), "`long` must be a string"));
|
||||
}
|
||||
}
|
||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("long") => {
|
||||
return Err(Error::new(
|
||||
list.path.span(),
|
||||
"`long` does not take any arguments",
|
||||
));
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("long") => {
|
||||
return Err(Error::new(p.span(), "`long` must be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("default") => {
|
||||
if let Lit::Str(default) = nv.lit {
|
||||
if opt.default.is_some() {
|
||||
return Err(Error::new(
|
||||
default.span(),
|
||||
"duplicate argument `default`",
|
||||
));
|
||||
}
|
||||
opt.default = Some(Some(default));
|
||||
} else {
|
||||
return Err(Error::new(nv.lit.span(), "`default` must be a string"));
|
||||
}
|
||||
return Err(Error::new(nv.lit.span(), "`default` cannot be assigned to"));
|
||||
}
|
||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("default") => {
|
||||
return Err(Error::new(
|
||||
@@ -797,13 +641,21 @@ pub fn parse_arg_attr(attr: Attribute, arg: PatType) -> Result<ArgOptions> {
|
||||
));
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("default") => {
|
||||
if opt.default.is_some() {
|
||||
return Err(Error::new(p.span(), "duplicate argument `default`"));
|
||||
}
|
||||
opt.default = Some(None);
|
||||
opt.clap_attr
|
||||
.push(NestedMeta::Meta(Meta::Path(Path::from(Ident::new(
|
||||
"default_value_t",
|
||||
p.span(),
|
||||
)))));
|
||||
opt.default = Some(p);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::new(arg.span(), "unknown argument"));
|
||||
unknown => {
|
||||
if opt.stdin.is_some() {
|
||||
return Err(Error::new(
|
||||
unknown.span(),
|
||||
"`stdin` and clap parser attributes are mutually exclusive",
|
||||
));
|
||||
}
|
||||
opt.clap_attr.push(unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,5 @@ macro_rules! macro_try {
|
||||
}
|
||||
|
||||
mod command;
|
||||
mod rpc_handler;
|
||||
mod rpc_server;
|
||||
mod run_cli;
|
||||
|
||||
pub use command::build::build as build_command;
|
||||
pub use rpc_handler::build::build as build_rpc_handler;
|
||||
pub use rpc_handler::RpcHandlerArgs;
|
||||
pub use rpc_server::build::build as build_rpc_server;
|
||||
pub use rpc_server::RpcServerArgs;
|
||||
pub use run_cli::build::build as build_run_cli;
|
||||
pub use run_cli::RunCliArgs;
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn build(args: RpcHandlerArgs) -> TokenStream {
|
||||
let mut command = args.command;
|
||||
let mut arguments = std::mem::replace(
|
||||
&mut command.segments.last_mut().unwrap().arguments,
|
||||
PathArguments::None,
|
||||
);
|
||||
let command_module = command.clone();
|
||||
if let PathArguments::AngleBracketed(a) = &mut arguments {
|
||||
a.args.push(syn::parse2(quote! { _ }).unwrap());
|
||||
}
|
||||
command.segments.push(PathSegment {
|
||||
ident: Ident::new("rpc_handler", command.span()),
|
||||
arguments,
|
||||
});
|
||||
let ctx = args.ctx;
|
||||
let parent_data = if let Some(data) = args.parent_data {
|
||||
quote! { #data }
|
||||
} else {
|
||||
quote! { () }
|
||||
};
|
||||
let status_fn = args.status_fn.unwrap_or_else(|| {
|
||||
syn::parse2(quote! { |_| ::rpc_toolkit::hyper::StatusCode::OK }).unwrap()
|
||||
});
|
||||
let middleware_name_clone = (0..)
|
||||
.map(|i| {
|
||||
Ident::new(
|
||||
&format!("__rpc_toolkit__rpc_handler__middleware_clone_{}", i),
|
||||
Span::call_site(),
|
||||
)
|
||||
})
|
||||
.take(args.middleware.len());
|
||||
let middleware_name_clone2 = middleware_name_clone.clone();
|
||||
let middleware_name_clone3 = middleware_name_clone.clone();
|
||||
let middleware_name_clone4 = middleware_name_clone.clone();
|
||||
let middleware_name_pre = (0..)
|
||||
.map(|i| Ident::new(&format!("middleware_pre_{}", i), Span::call_site()))
|
||||
.take(args.middleware.len());
|
||||
let middleware_name_pre2 = middleware_name_pre.clone();
|
||||
let middleware_name_post = (0..)
|
||||
.map(|i| Ident::new(&format!("middleware_post_{}", i), Span::call_site()))
|
||||
.take(args.middleware.len());
|
||||
let middleware_name_post_inv = middleware_name_post
|
||||
.clone()
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.rev();
|
||||
let middleware_name = (0..)
|
||||
.map(|i| Ident::new(&format!("middleware_{}", i), Span::call_site()))
|
||||
.take(args.middleware.len());
|
||||
let middleware_name2 = middleware_name.clone();
|
||||
let middleware = args.middleware.iter();
|
||||
let res = quote! {
|
||||
{
|
||||
let __rpc_toolkit__rpc_handler__context = #ctx;
|
||||
let __rpc_toolkit__rpc_handler__parent_data = #parent_data;
|
||||
let __rpc_toolkit__rpc_handler__status_fn = #status_fn;
|
||||
#(
|
||||
let #middleware_name_clone = ::std::sync::Arc::new(#middleware);
|
||||
)*
|
||||
let res: ::rpc_toolkit::RpcHandler = ::std::sync::Arc::new(move |mut req| {
|
||||
let ctx = __rpc_toolkit__rpc_handler__context.clone();
|
||||
let parent_data = __rpc_toolkit__rpc_handler__parent_data.clone();
|
||||
let metadata = #command_module::Metadata::default();
|
||||
#(
|
||||
let #middleware_name_clone3 = #middleware_name_clone2.clone();
|
||||
)*
|
||||
::rpc_toolkit::futures::FutureExt::boxed(async move {
|
||||
#(
|
||||
let #middleware_name_pre = match ::rpc_toolkit::rpc_server_helpers::constrain_middleware(&*#middleware_name_clone4)(&mut req, metadata).await? {
|
||||
Ok(a) => a,
|
||||
Err(res) => return Ok(res),
|
||||
};
|
||||
)*
|
||||
let (mut req_parts, req_body) = req.into_parts();
|
||||
let (mut res_parts, _) = ::rpc_toolkit::hyper::Response::new(()).into_parts();
|
||||
let rpc_req = ::rpc_toolkit::rpc_server_helpers::make_request(&req_parts, req_body).await;
|
||||
match rpc_req {
|
||||
Ok(mut rpc_req) => {
|
||||
#(
|
||||
let #middleware_name_post = match #middleware_name_pre2(&mut req_parts, &mut rpc_req).await? {
|
||||
Ok(a) => a,
|
||||
Err(res) => return Ok(res),
|
||||
};
|
||||
)*
|
||||
let mut rpc_res = match ::rpc_toolkit::serde_json::from_value(::rpc_toolkit::serde_json::Value::Object(rpc_req.params)) {
|
||||
Ok(params) => #command(ctx, parent_data, &req_parts, &mut res_parts, ::rpc_toolkit::yajrc::RpcMethod::as_str(&rpc_req.method), params).await,
|
||||
Err(e) => Err(e.into())
|
||||
};
|
||||
#(
|
||||
let #middleware_name = match #middleware_name_post_inv(&mut res_parts, &mut rpc_res).await? {
|
||||
Ok(a) => a,
|
||||
Err(res) => return Ok(res),
|
||||
};
|
||||
)*
|
||||
let mut res = ::rpc_toolkit::rpc_server_helpers::to_response(
|
||||
&req_parts.headers,
|
||||
res_parts,
|
||||
Ok((
|
||||
rpc_req.id,
|
||||
rpc_res,
|
||||
)),
|
||||
__rpc_toolkit__rpc_handler__status_fn,
|
||||
)?;
|
||||
#(
|
||||
#middleware_name2(&mut res).await?;
|
||||
)*
|
||||
Ok::<_, ::rpc_toolkit::hyper::http::Error>(res)
|
||||
}
|
||||
Err(e) => ::rpc_toolkit::rpc_server_helpers::to_response(
|
||||
&req_parts.headers,
|
||||
res_parts,
|
||||
Err(e),
|
||||
__rpc_toolkit__rpc_handler__status_fn,
|
||||
),
|
||||
}
|
||||
})
|
||||
});
|
||||
res
|
||||
}
|
||||
};
|
||||
// panic!("{}", res);
|
||||
res
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use syn::*;
|
||||
|
||||
pub struct RpcHandlerArgs {
|
||||
pub(crate) command: Path,
|
||||
pub(crate) ctx: Expr,
|
||||
pub(crate) parent_data: Option<Expr>,
|
||||
pub(crate) status_fn: Option<Expr>,
|
||||
pub(crate) middleware: punctuated::Punctuated<Expr, token::Comma>,
|
||||
}
|
||||
|
||||
pub mod build;
|
||||
mod parse;
|
||||
@@ -1,50 +0,0 @@
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl Parse for RpcHandlerArgs {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let args;
|
||||
braced!(args in input);
|
||||
let mut command = None;
|
||||
let mut ctx = None;
|
||||
let mut parent_data = None;
|
||||
let mut status_fn = None;
|
||||
let mut middleware = Punctuated::new();
|
||||
while !args.is_empty() {
|
||||
let arg_name: syn::Ident = args.parse()?;
|
||||
let _: token::Colon = args.parse()?;
|
||||
match arg_name.to_string().as_str() {
|
||||
"command" => {
|
||||
command = Some(args.parse()?);
|
||||
}
|
||||
"context" => {
|
||||
ctx = Some(args.parse()?);
|
||||
}
|
||||
"parent_data" => {
|
||||
parent_data = Some(args.parse()?);
|
||||
}
|
||||
"status" => {
|
||||
status_fn = Some(args.parse()?);
|
||||
}
|
||||
"middleware" => {
|
||||
let middlewares;
|
||||
bracketed!(middlewares in args);
|
||||
middleware = middlewares.parse_terminated(Expr::parse)?;
|
||||
}
|
||||
_ => return Err(Error::new(arg_name.span(), "unknown argument")),
|
||||
}
|
||||
if !args.is_empty() {
|
||||
let _: token::Comma = args.parse()?;
|
||||
}
|
||||
}
|
||||
Ok(RpcHandlerArgs {
|
||||
command: command.expect("`command` is required"),
|
||||
ctx: ctx.expect("`context` is required"),
|
||||
parent_data,
|
||||
status_fn,
|
||||
middleware,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn build(mut args: RpcServerArgs) -> TokenStream {
|
||||
let ctx = std::mem::replace(
|
||||
&mut args.ctx,
|
||||
parse2(quote! { __rpc_toolkit__rpc_server__context }).unwrap(),
|
||||
);
|
||||
let handler = crate::rpc_handler::build::build(args);
|
||||
let res = quote! {
|
||||
{
|
||||
let __rpc_toolkit__rpc_server__context = #ctx;
|
||||
let __rpc_toolkit__rpc_server__builder = ::rpc_toolkit::rpc_server_helpers::make_builder(&__rpc_toolkit__rpc_server__context);
|
||||
let handler = #handler;
|
||||
__rpc_toolkit__rpc_server__builder.serve(::rpc_toolkit::hyper::service::make_service_fn(move |_| {
|
||||
let handler = handler.clone();
|
||||
async move { Ok::<_, ::std::convert::Infallible>(::rpc_toolkit::hyper::service::service_fn(move |req| handler(req))) }
|
||||
}))
|
||||
}
|
||||
};
|
||||
// panic!("{}", res);
|
||||
res
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
use syn::*;
|
||||
|
||||
pub type RpcServerArgs = crate::RpcHandlerArgs;
|
||||
|
||||
pub mod build;
|
||||
@@ -1,81 +0,0 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn build(args: RunCliArgs) -> TokenStream {
|
||||
let mut command_handler = args.command.clone();
|
||||
let mut arguments = std::mem::replace(
|
||||
&mut command_handler.segments.last_mut().unwrap().arguments,
|
||||
PathArguments::None,
|
||||
);
|
||||
let command = command_handler.clone();
|
||||
if let PathArguments::AngleBracketed(a) = &mut arguments {
|
||||
a.args.push(syn::parse2(quote! { () }).unwrap());
|
||||
a.args.push(syn::parse2(quote! { _ }).unwrap());
|
||||
}
|
||||
command_handler.segments.push(PathSegment {
|
||||
ident: Ident::new("cli_handler", command.span()),
|
||||
arguments,
|
||||
});
|
||||
let app = if let Some(mut_app) = args.mut_app {
|
||||
let ident = mut_app.app_ident;
|
||||
let body = mut_app.body;
|
||||
quote! {
|
||||
{
|
||||
let #ident = #command::build_app();
|
||||
#body
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! { #command::build_app() }
|
||||
};
|
||||
let make_ctx = if let Some(make_ctx) = args.make_ctx {
|
||||
let ident = make_ctx.matches_ident;
|
||||
let body = make_ctx.body;
|
||||
quote! {
|
||||
{
|
||||
let #ident = &rpc_toolkit_matches;
|
||||
#body
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! { &rpc_toolkit_matches }
|
||||
};
|
||||
let parent_data = if let Some(data) = args.parent_data {
|
||||
quote! { #data }
|
||||
} else {
|
||||
quote! { () }
|
||||
};
|
||||
let exit_fn = args.exit_fn.unwrap_or_else(|| {
|
||||
syn::parse2(quote! { |err: ::rpc_toolkit::yajrc::RpcError| {
|
||||
eprintln!("{}", err.message);
|
||||
if let Some(data) = err.data {
|
||||
eprintln!("{}", data);
|
||||
}
|
||||
std::process::exit(err.code);
|
||||
} })
|
||||
.unwrap()
|
||||
});
|
||||
quote! {
|
||||
{
|
||||
let rpc_toolkit_matches = #app.get_matches();
|
||||
let rpc_toolkit_ctx = #make_ctx;
|
||||
let rpc_toolkit_parent_data = #parent_data;
|
||||
if let Err(err) = #command_handler(
|
||||
rpc_toolkit_ctx,
|
||||
rpc_toolkit_parent_data,
|
||||
None,
|
||||
&rpc_toolkit_matches,
|
||||
"".into(),
|
||||
(),
|
||||
) {
|
||||
drop(rpc_toolkit_matches);
|
||||
(#exit_fn)(err);
|
||||
} else {
|
||||
drop(rpc_toolkit_matches);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
use syn::*;
|
||||
|
||||
pub struct MakeCtx {
|
||||
matches_ident: Ident,
|
||||
body: Expr,
|
||||
}
|
||||
|
||||
pub struct MutApp {
|
||||
app_ident: Ident,
|
||||
body: Expr,
|
||||
}
|
||||
|
||||
pub struct RunCliArgs {
|
||||
command: Path,
|
||||
mut_app: Option<MutApp>,
|
||||
make_ctx: Option<MakeCtx>,
|
||||
parent_data: Option<Expr>,
|
||||
exit_fn: Option<Expr>,
|
||||
}
|
||||
|
||||
pub mod build;
|
||||
mod parse;
|
||||
@@ -1,68 +0,0 @@
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
|
||||
use super::*;
|
||||
|
||||
impl Parse for MakeCtx {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let matches_ident = input.parse()?;
|
||||
let _: token::FatArrow = input.parse()?;
|
||||
let body = input.parse()?;
|
||||
Ok(MakeCtx {
|
||||
matches_ident,
|
||||
body,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for MutApp {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let app_ident = input.parse()?;
|
||||
let _: token::FatArrow = input.parse()?;
|
||||
let body = input.parse()?;
|
||||
Ok(MutApp { app_ident, body })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for RunCliArgs {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let args;
|
||||
braced!(args in input);
|
||||
let mut command = None;
|
||||
let mut mut_app = None;
|
||||
let mut make_ctx = None;
|
||||
let mut parent_data = None;
|
||||
let mut exit_fn = None;
|
||||
while !args.is_empty() {
|
||||
let arg_name: syn::Ident = args.parse()?;
|
||||
let _: token::Colon = args.parse()?;
|
||||
match arg_name.to_string().as_str() {
|
||||
"command" => {
|
||||
command = Some(args.parse()?);
|
||||
}
|
||||
"app" => {
|
||||
mut_app = Some(args.parse()?);
|
||||
}
|
||||
"context" => {
|
||||
make_ctx = Some(args.parse()?);
|
||||
}
|
||||
"parent_data" => {
|
||||
parent_data = Some(args.parse()?);
|
||||
}
|
||||
"exit" => {
|
||||
exit_fn = Some(args.parse()?);
|
||||
}
|
||||
_ => return Err(Error::new(arg_name.span(), "unknown argument")),
|
||||
}
|
||||
if !args.is_empty() {
|
||||
let _: token::Comma = args.parse()?;
|
||||
}
|
||||
}
|
||||
Ok(RunCliArgs {
|
||||
command: command.expect("`command` is required"),
|
||||
mut_app,
|
||||
make_ctx,
|
||||
parent_data,
|
||||
exit_fn,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user