mirror of
https://github.com/Start9Labs/rpc-toolkit.git
synced 2026-03-26 02:11:56 +00:00
un-workspace
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
target/
|
target/
|
||||||
|
rpc.sock
|
||||||
44
Cargo.toml
44
Cargo.toml
@@ -1,2 +1,42 @@
|
|||||||
[workspace]
|
[package]
|
||||||
members = ["rpc-toolkit", "rpc-toolkit-macro", "rpc-toolkit-macro-internals"]
|
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
||||||
|
edition = "2018"
|
||||||
|
name = "rpc-toolkit"
|
||||||
|
version = "0.2.3"
|
||||||
|
description = "A toolkit for creating JSON-RPC 2.0 servers with automatic cli bindings"
|
||||||
|
license = "MIT"
|
||||||
|
documentation = "https://docs.rs/rpc-toolkit"
|
||||||
|
keywords = ["json", "rpc", "cli"]
|
||||||
|
repository = "https://github.com/Start9Labs/rpc-toolkit"
|
||||||
|
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[features]
|
||||||
|
cbor = ["serde_cbor"]
|
||||||
|
default = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
axum = "0.7.3"
|
||||||
|
async-stream = "0.3"
|
||||||
|
async-trait = "0.1"
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
futures = "0.3"
|
||||||
|
http = "1"
|
||||||
|
http-body-util = "0.1"
|
||||||
|
# hyper = { version = "1", features = ["server", "http1", "http2", "client"] }
|
||||||
|
itertools = "0.12"
|
||||||
|
imbl-value = { git = "https://github.com/Start9Labs/imbl-value.git" }
|
||||||
|
lazy_format = "2"
|
||||||
|
lazy_static = "1.4"
|
||||||
|
openssl = { version = "0.10", features = ["vendored"] }
|
||||||
|
pin-project = "1"
|
||||||
|
reqwest = { version = "0.11" }
|
||||||
|
rpc-toolkit-macro = { version = "0.2.2", path = "../rpc-toolkit-macro" }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_cbor = { version = "0.11", optional = true }
|
||||||
|
serde_json = "1.0"
|
||||||
|
thiserror = "1.0"
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
tokio-stream = { version = "0.1", features = ["io-util", "net"] }
|
||||||
|
url = "2"
|
||||||
|
yajrc = "0.1"
|
||||||
|
|||||||
2
rpc-toolkit-macro-internals/.gitignore
vendored
2
rpc-toolkit-macro-internals/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
/target
|
|
||||||
Cargo.lock
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[package]
|
|
||||||
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
|
||||||
edition = "2018"
|
|
||||||
name = "rpc-toolkit-macro-internals"
|
|
||||||
version = "0.2.2"
|
|
||||||
description = "internals for macros for rpc-toolkit"
|
|
||||||
license = "MIT"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
[dependencies]
|
|
||||||
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
@@ -1,102 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use syn::*;
|
|
||||||
|
|
||||||
pub mod build;
|
|
||||||
mod parse;
|
|
||||||
|
|
||||||
pub enum ExecutionContext {
|
|
||||||
Standard,
|
|
||||||
CliOnly(Path),
|
|
||||||
RpcOnly(Path),
|
|
||||||
Local(Path),
|
|
||||||
CustomCli {
|
|
||||||
custom: Path,
|
|
||||||
cli: Path,
|
|
||||||
context: Type,
|
|
||||||
is_async: bool,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
impl Default for ExecutionContext {
|
|
||||||
fn default() -> Self {
|
|
||||||
ExecutionContext::Standard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct LeafOptions {
|
|
||||||
macro_debug: Option<Path>,
|
|
||||||
blocking: Option<Path>,
|
|
||||||
is_async: bool,
|
|
||||||
aliases: Vec<LitStr>,
|
|
||||||
about: Option<LitStr>,
|
|
||||||
rename: Option<LitStr>,
|
|
||||||
exec_ctx: ExecutionContext,
|
|
||||||
display: Option<Path>,
|
|
||||||
metadata: HashMap<Ident, Lit>,
|
|
||||||
clap_attr: Vec<NestedMeta>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SelfImplInfo {
|
|
||||||
path: Path,
|
|
||||||
context: Type,
|
|
||||||
is_async: bool,
|
|
||||||
blocking: bool,
|
|
||||||
}
|
|
||||||
pub struct ParentOptions {
|
|
||||||
common: LeafOptions,
|
|
||||||
subcommands: Vec<Path>,
|
|
||||||
self_impl: Option<SelfImplInfo>,
|
|
||||||
}
|
|
||||||
impl From<LeafOptions> for ParentOptions {
|
|
||||||
fn from(opt: LeafOptions) -> Self {
|
|
||||||
ParentOptions {
|
|
||||||
common: opt,
|
|
||||||
subcommands: Default::default(),
|
|
||||||
self_impl: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Options {
|
|
||||||
Leaf(LeafOptions),
|
|
||||||
Parent(ParentOptions),
|
|
||||||
}
|
|
||||||
impl Options {
|
|
||||||
fn to_parent(&mut self) -> Result<&mut ParentOptions> {
|
|
||||||
if let Options::Leaf(opt) = self {
|
|
||||||
*self = Options::Parent(std::mem::replace(opt, Default::default()).into());
|
|
||||||
}
|
|
||||||
Ok(match self {
|
|
||||||
Options::Parent(a) => a,
|
|
||||||
_ => unreachable!(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn common(&mut self) -> &mut LeafOptions {
|
|
||||||
match self {
|
|
||||||
Options::Leaf(ref mut opt) => opt,
|
|
||||||
Options::Parent(opt) => &mut opt.common,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ArgOptions {
|
|
||||||
ty: Type,
|
|
||||||
name: Option<Ident>,
|
|
||||||
rename: Option<LitStr>,
|
|
||||||
parse: Option<Path>,
|
|
||||||
stdin: Option<Path>,
|
|
||||||
default: Option<Path>,
|
|
||||||
clap_attr: Vec<NestedMeta>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum ParamType {
|
|
||||||
None,
|
|
||||||
Arg(ArgOptions),
|
|
||||||
Context(Type),
|
|
||||||
ParentData(Type),
|
|
||||||
Request,
|
|
||||||
Response,
|
|
||||||
}
|
|
||||||
@@ -1,851 +0,0 @@
|
|||||||
use syn::spanned::Spanned;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn parse_command_attr(args: AttributeArgs) -> Result<Options> {
|
|
||||||
let mut opt = Options::Leaf(Default::default());
|
|
||||||
for arg in args {
|
|
||||||
match arg {
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("macro_debug") => {
|
|
||||||
opt.common().macro_debug = Some(p);
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("subcommands") => {
|
|
||||||
let inner = opt.to_parent()?;
|
|
||||||
if !inner.subcommands.is_empty() {
|
|
||||||
return Err(Error::new(list.span(), "duplicate argument `subcommands`"));
|
|
||||||
}
|
|
||||||
for subcmd in list.nested {
|
|
||||||
match subcmd {
|
|
||||||
NestedMeta::Meta(Meta::Path(subcmd)) => inner.subcommands.push(subcmd),
|
|
||||||
NestedMeta::Lit(Lit::Str(s)) => {
|
|
||||||
inner.subcommands.push(syn::parse_str(&s.value())?)
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(mut self_impl))
|
|
||||||
if self_impl.path.is_ident("self") =>
|
|
||||||
{
|
|
||||||
if self_impl.nested.len() == 1 {
|
|
||||||
match self_impl.nested.pop().unwrap().into_value() {
|
|
||||||
NestedMeta::Meta(Meta::Path(self_impl)) => {
|
|
||||||
if inner.self_impl.is_some() {
|
|
||||||
return Err(Error::new(
|
|
||||||
self_impl.span(),
|
|
||||||
"duplicate argument `self`",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
inner.self_impl = Some(SelfImplInfo {
|
|
||||||
path: self_impl,
|
|
||||||
context: parse2(quote::quote! { () }).unwrap(),
|
|
||||||
is_async: false,
|
|
||||||
blocking: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(l)) => {
|
|
||||||
if inner.self_impl.is_some() {
|
|
||||||
return Err(Error::new(
|
|
||||||
self_impl.span(),
|
|
||||||
"duplicate argument `self`",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let mut is_async = false;
|
|
||||||
let mut blocking = false;
|
|
||||||
let mut context: Type =
|
|
||||||
parse2(quote::quote! { () }).unwrap();
|
|
||||||
for meta in &l.nested {
|
|
||||||
match meta {
|
|
||||||
NestedMeta::Meta(Meta::Path(p))
|
|
||||||
if p.is_ident("async") =>
|
|
||||||
{
|
|
||||||
is_async = true;
|
|
||||||
if blocking {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`async` and `blocking` are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p))
|
|
||||||
if p.is_ident("blocking") =>
|
|
||||||
{
|
|
||||||
blocking = true;
|
|
||||||
if is_async {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`async` and `blocking` are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(p))
|
|
||||||
if p.path.is_ident("context") =>
|
|
||||||
{
|
|
||||||
context = if let Some(NestedMeta::Meta(
|
|
||||||
Meta::Path(context),
|
|
||||||
)) = p.nested.first()
|
|
||||||
{
|
|
||||||
Type::Path(TypePath {
|
|
||||||
path: context.clone(),
|
|
||||||
qself: None,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`context` requires a path argument",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arg => {
|
|
||||||
return Err(Error::new(
|
|
||||||
arg.span(),
|
|
||||||
"unknown argument",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inner.self_impl = Some(SelfImplInfo {
|
|
||||||
path: l.path,
|
|
||||||
context,
|
|
||||||
is_async,
|
|
||||||
blocking,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
a => {
|
|
||||||
return Err(Error::new(
|
|
||||||
a.span(),
|
|
||||||
"`self` implementation must be a path, or a list",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
self_impl.nested.span(),
|
|
||||||
"`self` can only have one implementation",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arg => {
|
|
||||||
return Err(Error::new(arg.span(), "unknown argument to `subcommands`"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if inner.subcommands.is_empty() {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`subcommands` requires at least 1 argument",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("subcommands") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`subcommands` requires at least 1 argument",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("subcommands") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
nv.path.span(),
|
|
||||||
"`subcommands` cannot be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("display") => {
|
|
||||||
if list.nested.len() == 1 {
|
|
||||||
match &list.nested[0] {
|
|
||||||
NestedMeta::Meta(Meta::Path(display_impl)) => {
|
|
||||||
if opt.common().display.is_some() {
|
|
||||||
return Err(Error::new(
|
|
||||||
display_impl.span(),
|
|
||||||
"duplicate argument `display`",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
opt.common().display = Some(display_impl.clone())
|
|
||||||
}
|
|
||||||
a => {
|
|
||||||
return Err(Error::new(
|
|
||||||
a.span(),
|
|
||||||
"`display` implementation must be a path",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.nested.span(),
|
|
||||||
"`display` can only have one implementation",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("display") => {
|
|
||||||
return Err(Error::new(p.span(), "`display` requires an argument"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("display") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
nv.path.span(),
|
|
||||||
"`display` cannot be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("custom_cli") => {
|
|
||||||
if list.nested.len() == 1 {
|
|
||||||
match &opt.common().exec_ctx {
|
|
||||||
ExecutionContext::Standard => match &list.nested[0] {
|
|
||||||
NestedMeta::Meta(Meta::Path(custom_cli_impl)) => {
|
|
||||||
opt.common().exec_ctx = ExecutionContext::CustomCli {
|
|
||||||
custom: list.path,
|
|
||||||
context: parse2(quote::quote!{ () }).unwrap(),
|
|
||||||
cli: custom_cli_impl.clone(),
|
|
||||||
is_async: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(custom_cli_impl)) => {
|
|
||||||
let mut is_async = false;
|
|
||||||
let mut context: Type = parse2(quote::quote! { () }).unwrap();
|
|
||||||
for meta in &custom_cli_impl.nested {
|
|
||||||
match meta {
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("async") => is_async = true,
|
|
||||||
NestedMeta::Meta(Meta::List(p)) if p.path.is_ident("context") => {
|
|
||||||
context = if let Some(NestedMeta::Meta(Meta::Path(context))) = p.nested.first() {
|
|
||||||
Type::Path(TypePath {
|
|
||||||
path: context.clone(),
|
|
||||||
qself: None,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(p.span(), "`context` requires a path argument"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arg => return Err(Error::new(arg.span(), "unknown argument")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opt.common().exec_ctx = ExecutionContext::CustomCli {
|
|
||||||
custom: list.path,
|
|
||||||
context,
|
|
||||||
cli: custom_cli_impl.path.clone(),
|
|
||||||
is_async,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
a => {
|
|
||||||
return Err(Error::new(
|
|
||||||
a.span(),
|
|
||||||
"`custom_cli` implementation must be a path, or a list with 1 argument",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ExecutionContext::CliOnly(_) => {
|
|
||||||
return Err(Error::new(list.span(), "duplicate argument: `cli_only`"))
|
|
||||||
}
|
|
||||||
ExecutionContext::RpcOnly(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.span(),
|
|
||||||
"`cli_only` and `rpc_only` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::Local(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.span(),
|
|
||||||
"`cli_only` and `local` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::CustomCli { .. } => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.span(),
|
|
||||||
"`cli_only` and `custom_cli` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.nested.span(),
|
|
||||||
"`custom_cli` can only have one implementation",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("custom_cli") => {
|
|
||||||
return Err(Error::new(p.span(), "`custom_cli` requires an argument"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("custom_cli") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
nv.path.span(),
|
|
||||||
"`custom_cli` cannot be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("aliases") => {
|
|
||||||
if !opt.common().aliases.is_empty() {
|
|
||||||
return Err(Error::new(list.span(), "duplicate argument `alias`"));
|
|
||||||
}
|
|
||||||
for nested in list.nested {
|
|
||||||
match nested {
|
|
||||||
NestedMeta::Lit(Lit::Str(alias)) => opt.common().aliases.push(alias),
|
|
||||||
a => return Err(Error::new(a.span(), "`alias` must be a string")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("alias") => {
|
|
||||||
return Err(Error::new(p.span(), "`alias` requires an argument"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("alias") => {
|
|
||||||
if !opt.common().aliases.is_empty() {
|
|
||||||
return Err(Error::new(nv.path.span(), "duplicate argument `alias`"));
|
|
||||||
}
|
|
||||||
if let Lit::Str(alias) = nv.lit {
|
|
||||||
opt.common().aliases.push(alias);
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(nv.lit.span(), "`alias` must be a string"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("cli_only") => {
|
|
||||||
match &opt.common().exec_ctx {
|
|
||||||
ExecutionContext::Standard => {
|
|
||||||
opt.common().exec_ctx = ExecutionContext::CliOnly(p)
|
|
||||||
}
|
|
||||||
ExecutionContext::CliOnly(_) => {
|
|
||||||
return Err(Error::new(p.span(), "duplicate argument: `cli_only`"))
|
|
||||||
}
|
|
||||||
ExecutionContext::RpcOnly(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`cli_only` and `rpc_only` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::Local(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`cli_only` and `local` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::CustomCli { .. } => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`cli_only` and `custom_cli` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("cli_only") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`cli_only` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("cli_only") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
nv.path.span(),
|
|
||||||
"`cli_only` cannot be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("rpc_only") => {
|
|
||||||
match &opt.common().exec_ctx {
|
|
||||||
ExecutionContext::Standard => {
|
|
||||||
opt.common().exec_ctx = ExecutionContext::RpcOnly(p)
|
|
||||||
}
|
|
||||||
ExecutionContext::RpcOnly(_) => {
|
|
||||||
return Err(Error::new(p.span(), "duplicate argument: `rpc_only`"))
|
|
||||||
}
|
|
||||||
ExecutionContext::CliOnly(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`rpc_only` and `cli_only` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::Local(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`rpc_only` and `local` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::CustomCli { .. } => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`rpc_only` and `custom_cli` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("rpc_only") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`rpc_only` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("rpc_only") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
nv.path.span(),
|
|
||||||
"`rpc_only` cannot be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("local") => {
|
|
||||||
match &opt.common().exec_ctx {
|
|
||||||
ExecutionContext::Standard => {
|
|
||||||
opt.common().exec_ctx = ExecutionContext::Local(p)
|
|
||||||
}
|
|
||||||
ExecutionContext::Local(_) => {
|
|
||||||
return Err(Error::new(p.span(), "duplicate argument: `local`"))
|
|
||||||
}
|
|
||||||
ExecutionContext::RpcOnly(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`local` and `rpc_only` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::CliOnly(_) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`local` and `cli_only` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::CustomCli { .. } => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`local` and `custom_cli` are mutually exclusive",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("local") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`local` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("local") => {
|
|
||||||
return Err(Error::new(nv.path.span(), "`local` cannot be assigned to"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("blocking") => {
|
|
||||||
if opt.common().blocking.is_some() {
|
|
||||||
return Err(Error::new(p.span(), "duplicate argument `blocking`"));
|
|
||||||
}
|
|
||||||
opt.common().blocking = Some(p);
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("blocking") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`blocking` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("blocking") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
nv.path.span(),
|
|
||||||
"`blocking` cannot be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("about") => {
|
|
||||||
if let Lit::Str(about) = nv.lit {
|
|
||||||
if opt.common().about.is_some() {
|
|
||||||
return Err(Error::new(about.span(), "duplicate argument `about`"));
|
|
||||||
}
|
|
||||||
opt.common().about = Some(about);
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(nv.lit.span(), "about message must be a string"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("about") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`about` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("about") => {
|
|
||||||
return Err(Error::new(p.span(), "`about` must be assigned to"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("rename") => {
|
|
||||||
if let Lit::Str(rename) = nv.lit {
|
|
||||||
if opt.common().rename.is_some() {
|
|
||||||
return Err(Error::new(rename.span(), "duplicate argument `rename`"));
|
|
||||||
}
|
|
||||||
opt.common().rename = Some(rename);
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(nv.lit.span(), "`rename` must be a string"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("rename") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`rename` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("rename") => {
|
|
||||||
return Err(Error::new(p.span(), "`rename` must be assigned to"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("metadata") => {
|
|
||||||
for meta in list.nested {
|
|
||||||
match meta {
|
|
||||||
NestedMeta::Meta(Meta::NameValue(metadata_pair)) => {
|
|
||||||
let ident = metadata_pair.path.get_ident().ok_or(Error::new(
|
|
||||||
metadata_pair.path.span(),
|
|
||||||
"must be an identifier",
|
|
||||||
))?;
|
|
||||||
if opt
|
|
||||||
.common()
|
|
||||||
.metadata
|
|
||||||
.insert(ident.clone(), metadata_pair.lit)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
return Err(Error::new(
|
|
||||||
ident.span(),
|
|
||||||
format!("duplicate metadata `{}`", ident),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a => {
|
|
||||||
return Err(Error::new(
|
|
||||||
a.span(),
|
|
||||||
"`metadata` takes a list of identifiers to be assigned to",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("metadata") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`metadata` takes a list of identifiers to be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("metadata") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
nv.path.span(),
|
|
||||||
"`metadata` cannot be assigned to",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::new(arg.span(), "unknown argument"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Options::Parent(opt) = &opt {
|
|
||||||
if opt.self_impl.is_none() {
|
|
||||||
if let Some(display) = &opt.common.display {
|
|
||||||
return Err(Error::new(
|
|
||||||
display.span(),
|
|
||||||
"cannot define `display` for a command without an implementation",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
match &opt.common.exec_ctx {
|
|
||||||
ExecutionContext::CliOnly(cli_only) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
cli_only.span(),
|
|
||||||
"cannot define `cli_only` for a command without an implementation",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
ExecutionContext::RpcOnly(rpc_only) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
rpc_only.span(),
|
|
||||||
"cannot define `rpc_only` for a command without an implementation",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(opt)
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
name: match *arg.pat {
|
|
||||||
Pat::Ident(i) => Some(i.ident),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
rename: None,
|
|
||||||
parse: None,
|
|
||||||
stdin: None,
|
|
||||||
default: None,
|
|
||||||
clap_attr: Vec::new(),
|
|
||||||
};
|
|
||||||
match meta {
|
|
||||||
Meta::List(list) => {
|
|
||||||
for arg in list.nested {
|
|
||||||
match arg {
|
|
||||||
NestedMeta::Meta(Meta::List(mut list)) if list.path.is_ident("parse") => {
|
|
||||||
if list.nested.len() == 1 {
|
|
||||||
match list.nested.pop().unwrap().into_value() {
|
|
||||||
NestedMeta::Meta(Meta::Path(parse_impl)) => {
|
|
||||||
if opt.parse.is_some() {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.span(),
|
|
||||||
"duplicate argument `parse`",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
opt.parse = Some(parse_impl)
|
|
||||||
}
|
|
||||||
a => {
|
|
||||||
return Err(Error::new(
|
|
||||||
a.span(),
|
|
||||||
"`parse` implementation must be a path",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.nested.span(),
|
|
||||||
"`parse` can only have one implementation",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("parse") => {
|
|
||||||
return Err(Error::new(p.span(), "`parse` requires an argument"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("parse") => {
|
|
||||||
return Err(Error::new(nv.path.span(), "`parse` cannot be assigned to"));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("stdin") => {
|
|
||||||
if !opt.clap_attr.is_empty() {
|
|
||||||
return Err(Error::new(
|
|
||||||
p.span(),
|
|
||||||
"`stdin` and clap parser attributes are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
opt.stdin = Some(p);
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("stdin") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`stdin` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
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::NameValue(nv)) if nv.path.is_ident("rename") => {
|
|
||||||
if let Lit::Str(rename) = nv.lit {
|
|
||||||
if opt.rename.is_some() {
|
|
||||||
return Err(Error::new(
|
|
||||||
rename.span(),
|
|
||||||
"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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::List(list)) if list.path.is_ident("rename") => {
|
|
||||||
return Err(Error::new(
|
|
||||||
list.path.span(),
|
|
||||||
"`rename` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
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("default") => {
|
|
||||||
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(
|
|
||||||
list.path.span(),
|
|
||||||
"`default` does not take any arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("default") => {
|
|
||||||
opt.clap_attr
|
|
||||||
.push(NestedMeta::Meta(Meta::Path(Path::from(Ident::new(
|
|
||||||
"default_value_t",
|
|
||||||
p.span(),
|
|
||||||
)))));
|
|
||||||
opt.default = Some(p);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Meta::Path(_) => (),
|
|
||||||
Meta::NameValue(nv) => return Err(Error::new(nv.span(), "`arg` cannot be assigned to")),
|
|
||||||
}
|
|
||||||
if opt.name.is_none() {
|
|
||||||
return Err(Error::new(
|
|
||||||
arg_span,
|
|
||||||
"cannot infer name for pattern argument",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(opt)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_param_attrs(item: &mut ItemFn) -> Result<Vec<ParamType>> {
|
|
||||||
let mut params = Vec::new();
|
|
||||||
for param in item.sig.inputs.iter_mut() {
|
|
||||||
if let FnArg::Typed(param) = param {
|
|
||||||
let mut ty = ParamType::None;
|
|
||||||
let mut i = 0;
|
|
||||||
while i != param.attrs.len() {
|
|
||||||
if param.attrs[i].path.is_ident("arg") {
|
|
||||||
let attr = param.attrs.remove(i);
|
|
||||||
if matches!(ty, ParamType::None) {
|
|
||||||
ty = ParamType::Arg(parse_arg_attr(attr, param.clone())?);
|
|
||||||
} else if matches!(ty, ParamType::Arg(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` attribute may only be specified once",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Context(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `context` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::ParentData(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `parent_data` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Request) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `request` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Response) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else if param.attrs[i].path.is_ident("context") {
|
|
||||||
let attr = param.attrs.remove(i);
|
|
||||||
if matches!(ty, ParamType::None) {
|
|
||||||
ty = ParamType::Context(*param.ty.clone());
|
|
||||||
} else if matches!(ty, ParamType::Context(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`context` attribute may only be specified once",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Arg(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `context` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::ParentData(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`context` and `parent_data` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Request) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`context` and `request` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Response) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`context` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else if param.attrs[i].path.is_ident("parent_data") {
|
|
||||||
let attr = param.attrs.remove(i);
|
|
||||||
if matches!(ty, ParamType::None) {
|
|
||||||
ty = ParamType::ParentData(*param.ty.clone());
|
|
||||||
} else if matches!(ty, ParamType::ParentData(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`parent_data` attribute may only be specified once",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Arg(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `parent_data` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Context(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`context` and `parent_data` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Request) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`parent_data` and `request` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Response) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`parent_data` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else if param.attrs[i].path.is_ident("request") {
|
|
||||||
let attr = param.attrs.remove(i);
|
|
||||||
if matches!(ty, ParamType::None) {
|
|
||||||
ty = ParamType::Request;
|
|
||||||
} else if matches!(ty, ParamType::Request) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`request` attribute may only be specified once",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Arg(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `request` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Context(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`context` and `request` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::ParentData(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`parent_data` and `request` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Response) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`request` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else if param.attrs[i].path.is_ident("response") {
|
|
||||||
let attr = param.attrs.remove(i);
|
|
||||||
if matches!(ty, ParamType::None) {
|
|
||||||
ty = ParamType::Response;
|
|
||||||
} else if matches!(ty, ParamType::Response) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`response` attribute may only be specified once",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Arg(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`arg` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Context(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`context` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::ParentData(_)) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`parent_data` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
} else if matches!(ty, ParamType::Request) {
|
|
||||||
return Err(Error::new(
|
|
||||||
attr.span(),
|
|
||||||
"`request` and `response` are mutually exclusive",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if matches!(ty, ParamType::None) {
|
|
||||||
return Err(Error::new(
|
|
||||||
param.span(),
|
|
||||||
"must specify either `arg`, `context`, `parent_data`, `request`, or `response` attributes",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
params.push(ty)
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
param.span(),
|
|
||||||
"commands may not take `self` as an argument",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(params)
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
macro_rules! macro_try {
|
|
||||||
($x:expr) => {
|
|
||||||
match $x {
|
|
||||||
Ok(a) => a,
|
|
||||||
Err(e) => return e.to_compile_error(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
mod command;
|
|
||||||
|
|
||||||
pub use command::build::build as build_command;
|
|
||||||
2
rpc-toolkit-macro/.gitignore
vendored
2
rpc-toolkit-macro/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
/target
|
|
||||||
Cargo.lock
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
[package]
|
|
||||||
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
|
||||||
edition = "2018"
|
|
||||||
name = "rpc-toolkit-macro"
|
|
||||||
version = "0.2.2"
|
|
||||||
description = "macros for rpc-toolkit"
|
|
||||||
license = "MIT"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
proc-macro2 = "1.0"
|
|
||||||
rpc-toolkit-macro-internals = { version = "=0.2.2", path = "../rpc-toolkit-macro-internals" }
|
|
||||||
syn = "1.0"
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
use proc_macro::{Span, TokenStream};
|
|
||||||
use rpc_toolkit_macro_internals::*;
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn command(args: TokenStream, item: TokenStream) -> TokenStream {
|
|
||||||
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
|
|
||||||
let item = syn::parse_macro_input!(item as syn::ItemFn);
|
|
||||||
build_command(args, item).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `#[arg(...)]` -> Take this argument as a parameter
|
|
||||||
/// - `#[arg(help = "Help text")]` -> Set help text for the arg
|
|
||||||
/// - `#[arg(alias = "ls")]` -> Set the alias `ls` in the CLI
|
|
||||||
/// - `#[arg(aliases("show", "ls"))]` -> Set the aliases `ls` and `show` in the CLI
|
|
||||||
/// - `#[arg(rename = "new_name")]` -> Set the name of the arg to `new_name` in the RPC and CLI
|
|
||||||
/// - `#[arg(short = "a")]` -> Set the "short" representation of the arg to `-a` on the CLI
|
|
||||||
/// - `#[arg(long = "arg")]` -> Set the "long" representation of the arg to `--arg` on the CLI
|
|
||||||
/// - `#[arg(parse(custom_parse_fn))]` -> Use the function `custom_parse_fn` to parse the arg from the CLI
|
|
||||||
/// - `custom_parse_fn :: Into<RpcError> err => (&str, &ArgMatches) -> Result<arg, err>`
|
|
||||||
/// - note: `arg` is the type of the argument
|
|
||||||
/// - `#[arg(stdin)]` -> Parse the argument from stdin when using the CLI
|
|
||||||
/// - `custom_parse_fn :: Into<RpcError> err => (&[u8], &ArgMatches) -> Result<arg, err>`
|
|
||||||
/// - `#[arg(count)]` -> Treat argument as flag, count occurrences
|
|
||||||
/// - `#[arg(multiple)]` -> Allow the arg to be specified multiple times. Collect the args after parsing.
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn arg(_: TokenStream, _: TokenStream) -> TokenStream {
|
|
||||||
syn::Error::new(
|
|
||||||
Span::call_site().into(),
|
|
||||||
"`arg` is only allowed on arguments of a function with the `command` attribute",
|
|
||||||
)
|
|
||||||
.to_compile_error()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// - `#[context]` -> Passes the application context into this parameter
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn context(_: TokenStream, _: TokenStream) -> TokenStream {
|
|
||||||
syn::Error::new(
|
|
||||||
Span::call_site().into(),
|
|
||||||
"`context` is only allowed on arguments of a function with the `command` attribute",
|
|
||||||
)
|
|
||||||
.to_compile_error()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
2
rpc-toolkit/.gitignore
vendored
2
rpc-toolkit/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
/target
|
|
||||||
Cargo.lock
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
[package]
|
|
||||||
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
|
||||||
edition = "2018"
|
|
||||||
name = "rpc-toolkit"
|
|
||||||
version = "0.2.3"
|
|
||||||
description = "A toolkit for creating JSON-RPC 2.0 servers with automatic cli bindings"
|
|
||||||
license = "MIT"
|
|
||||||
documentation = "https://docs.rs/rpc-toolkit"
|
|
||||||
keywords = ["json", "rpc", "cli"]
|
|
||||||
repository = "https://github.com/Start9Labs/rpc-toolkit"
|
|
||||||
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
[features]
|
|
||||||
cbor = ["serde_cbor"]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
axum = "0.7.3"
|
|
||||||
async-stream = "0.3"
|
|
||||||
async-trait = "0.1"
|
|
||||||
clap = { version = "4", features = ["derive"] }
|
|
||||||
futures = "0.3"
|
|
||||||
http = "1"
|
|
||||||
http-body-util = "0.1"
|
|
||||||
# hyper = { version = "1", features = ["server", "http1", "http2", "client"] }
|
|
||||||
itertools = "0.12"
|
|
||||||
imbl-value = { git = "https://github.com/Start9Labs/imbl-value.git" }
|
|
||||||
lazy_format = "2"
|
|
||||||
lazy_static = "1.4"
|
|
||||||
openssl = { version = "0.10", features = ["vendored"] }
|
|
||||||
pin-project = "1"
|
|
||||||
reqwest = { version = "0.11" }
|
|
||||||
rpc-toolkit-macro = { version = "0.2.2", path = "../rpc-toolkit-macro" }
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_cbor = { version = "0.11", optional = true }
|
|
||||||
serde_json = "1.0"
|
|
||||||
thiserror = "1.0"
|
|
||||||
tokio = { version = "1", features = ["full"] }
|
|
||||||
tokio-stream = { version = "0.1", features = ["io-util", "net"] }
|
|
||||||
url = "2"
|
|
||||||
yajrc = "0.1"
|
|
||||||
Reference in New Issue
Block a user