mirror of
https://github.com/Start9Labs/rpc-toolkit.git
synced 2026-03-26 02:11:56 +00:00
better root_handler handling
This commit is contained in:
879
Cargo.lock
generated
879
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -43,8 +43,8 @@ impl<Context: crate::Context + Clone, Config: CommandFactory + FromArgMatches>
|
||||
}
|
||||
pub fn run(self, args: impl IntoIterator<Item = OsString>) -> Result<(), RpcError> {
|
||||
let mut cmd = Config::command();
|
||||
for (name, handler) in &self.root_handler.subcommands.0 {
|
||||
if let (Name(Some(name)), Some(cli)) = (name, handler.cli()) {
|
||||
for (name, handler) in &self.root_handler.subcommands.1 {
|
||||
if let (Name(name), Some(cli)) = (name, handler.cli()) {
|
||||
cmd = cmd.subcommand(cli.cli_command().name(name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,32 +14,52 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) struct Name(pub(crate) Option<&'static str>);
|
||||
impl<'a> std::borrow::Borrow<Option<&'a str>> for Name {
|
||||
fn borrow(&self) -> &Option<&'a str> {
|
||||
pub(crate) struct Name(pub(crate) &'static str);
|
||||
impl<'a> std::borrow::Borrow<&'a str> for Name {
|
||||
fn borrow(&self) -> &&'a str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SubcommandMap<Context, Inherited>(
|
||||
pub(crate) OrdMap<Name, DynHandler<Context, Inherited>>,
|
||||
pub(crate) struct SubcommandMap<Context, Params, InheritedParams>(
|
||||
pub(crate) Option<DynHandler<Context, InheritedParams>>,
|
||||
pub(crate) OrdMap<Name, DynHandler<Context, Flat<Params, InheritedParams>>>,
|
||||
);
|
||||
impl<Context, Inherited> Clone for SubcommandMap<Context, Inherited> {
|
||||
impl<Context, Params, InheritedParams> Clone for SubcommandMap<Context, Params, InheritedParams> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
Self(self.0.clone(), self.1.clone())
|
||||
}
|
||||
}
|
||||
impl<Context, Inherited> Debug for SubcommandMap<Context, Inherited> {
|
||||
impl<Context, Params, InheritedParams> Debug for SubcommandMap<Context, Params, InheritedParams> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_map().entries(self.0.iter()).finish()
|
||||
let mut map = f.debug_map();
|
||||
if let Some(root) = &self.0 {
|
||||
#[derive(Debug)]
|
||||
struct Root;
|
||||
map.entry(&Root, root);
|
||||
}
|
||||
map.entries(self.1.iter()).finish()
|
||||
}
|
||||
}
|
||||
impl<Context, Inherited> SubcommandMap<Context, Inherited> {
|
||||
fn insert(&mut self, name: Option<&'static str>, handler: DynHandler<Context, Inherited>) {
|
||||
self.0.insert(Name(name), handler);
|
||||
impl<Context, Params, InheritedParams> SubcommandMap<Context, Params, InheritedParams> {
|
||||
fn set_root(&mut self, handler: DynHandler<Context, InheritedParams>) {
|
||||
self.0 = Some(handler);
|
||||
}
|
||||
fn get<'a>(&'a self, name: Option<&str>) -> Option<(Name, &'a DynHandler<Context, Inherited>)> {
|
||||
if let Some((name, handler)) = self.0.get_key_value(&name) {
|
||||
fn get_root<'a>(&'a self) -> Option<&'a DynHandler<Context, InheritedParams>> {
|
||||
self.0.as_ref()
|
||||
}
|
||||
fn insert(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
handler: DynHandler<Context, Flat<Params, InheritedParams>>,
|
||||
) {
|
||||
self.1.insert(Name(name), handler);
|
||||
}
|
||||
fn get<'a>(
|
||||
&'a self,
|
||||
name: &str,
|
||||
) -> Option<(Name, &'a DynHandler<Context, Flat<Params, InheritedParams>>)> {
|
||||
if let Some((name, handler)) = self.1.get_key_value(&name) {
|
||||
Some((*name, handler))
|
||||
} else {
|
||||
None
|
||||
@@ -49,14 +69,14 @@ impl<Context, Inherited> SubcommandMap<Context, Inherited> {
|
||||
|
||||
pub struct ParentHandler<Context, Params = Empty, InheritedParams = Empty> {
|
||||
_phantom: PhantomData<Context>,
|
||||
pub(crate) subcommands: SubcommandMap<Context, Flat<Params, InheritedParams>>,
|
||||
pub(crate) subcommands: SubcommandMap<Context, Params, InheritedParams>,
|
||||
metadata: OrdMap<&'static str, Value>,
|
||||
}
|
||||
impl<Context, Params, InheritedParams> ParentHandler<Context, Params, InheritedParams> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
_phantom: PhantomData::new(),
|
||||
subcommands: SubcommandMap(OrdMap::new()),
|
||||
subcommands: SubcommandMap(None, OrdMap::new()),
|
||||
metadata: OrdMap::new(),
|
||||
}
|
||||
}
|
||||
@@ -98,12 +118,11 @@ impl<Context: crate::Context, Params, InheritedParams>
|
||||
}
|
||||
pub fn root_handler<C: crate::Context, H>(mut self, handler: H) -> Self
|
||||
where
|
||||
WithContext<C, H>: Handler<Flat<Params, InheritedParams>>,
|
||||
<WithContext<C, H> as Handler<Flat<Params, InheritedParams>>>::H:
|
||||
HandlerTypes<Params = Empty>,
|
||||
WithContext<C, H>: Handler<InheritedParams>,
|
||||
<WithContext<C, H> as Handler<InheritedParams>>::H: HandlerTypes<Params = Params>,
|
||||
{
|
||||
if let Some(h) = DynHandler::new(handler) {
|
||||
self.subcommands.insert(None, h);
|
||||
self.subcommands.set_root(h);
|
||||
}
|
||||
self
|
||||
}
|
||||
@@ -142,7 +161,6 @@ where
|
||||
let cmd = method.pop_front();
|
||||
if let Some(cmd) = cmd {
|
||||
parent_method.push_back(cmd);
|
||||
}
|
||||
if let Some((_, sub_handler)) = &self.subcommands.get(cmd) {
|
||||
sub_handler.handle_sync(HandleAnyArgs {
|
||||
context,
|
||||
@@ -154,6 +172,19 @@ where
|
||||
} else {
|
||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||
}
|
||||
} else {
|
||||
if let Some(sub_handler) = &self.subcommands.get_root() {
|
||||
sub_handler.handle_sync(HandleAnyArgs {
|
||||
context,
|
||||
parent_method,
|
||||
method,
|
||||
params: raw_params,
|
||||
inherited: inherited_params,
|
||||
})
|
||||
} else {
|
||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn handle_async(
|
||||
&self,
|
||||
@@ -169,8 +200,7 @@ where
|
||||
let cmd = method.pop_front();
|
||||
if let Some(cmd) = cmd {
|
||||
parent_method.push_back(cmd);
|
||||
}
|
||||
if let Some((_, sub_handler)) = self.subcommands.get(cmd) {
|
||||
if let Some((_, sub_handler)) = &self.subcommands.get(cmd) {
|
||||
sub_handler
|
||||
.handle_async(HandleAnyArgs {
|
||||
context,
|
||||
@@ -183,14 +213,37 @@ where
|
||||
} else {
|
||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||
}
|
||||
} else {
|
||||
if let Some(sub_handler) = &self.subcommands.get_root() {
|
||||
sub_handler
|
||||
.handle_async(HandleAnyArgs {
|
||||
context,
|
||||
parent_method,
|
||||
method,
|
||||
params: raw_params,
|
||||
inherited: inherited_params,
|
||||
})
|
||||
.await
|
||||
} else {
|
||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn metadata(&self, mut method: VecDeque<&'static str>) -> OrdMap<&'static str, Value> {
|
||||
let metadata = self.metadata.clone();
|
||||
if let Some((_, handler)) = self.subcommands.get(method.pop_front()) {
|
||||
if let Some(cmd) = method.pop_front() {
|
||||
if let Some((_, handler)) = self.subcommands.get(cmd) {
|
||||
handler.metadata(method).union(metadata)
|
||||
} else {
|
||||
metadata
|
||||
}
|
||||
} else {
|
||||
if let Some(handler) = self.subcommands.get_root() {
|
||||
handler.metadata(method).union(metadata)
|
||||
} else {
|
||||
metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
fn method_from_dots(&self, method: &str) -> Option<VecDeque<&'static str>> {
|
||||
let (head, tail) = if method.is_empty() {
|
||||
@@ -201,15 +254,22 @@ where
|
||||
.map(|(head, tail)| (Some(head), Some(tail)))
|
||||
.unwrap_or((Some(method), None))
|
||||
};
|
||||
if let Some(head) = head {
|
||||
let (Name(name), h) = self.subcommands.get(head)?;
|
||||
let mut res = VecDeque::new();
|
||||
if let Some(name) = name {
|
||||
res.push_back(name);
|
||||
}
|
||||
if let Some(tail) = tail {
|
||||
res.append(&mut h.method_from_dots(tail)?);
|
||||
}
|
||||
Some(res)
|
||||
} else {
|
||||
let h = self.subcommands.get_root()?;
|
||||
let mut res = VecDeque::new();
|
||||
if let Some(tail) = tail {
|
||||
res.append(&mut h.method_from_dots(tail)?);
|
||||
}
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,15 +281,16 @@ where
|
||||
InheritedParams: Serialize + Send + Sync + 'static,
|
||||
{
|
||||
fn cli_command(&self) -> Command {
|
||||
let mut base = Params::command().subcommand_required(true);
|
||||
for (name, handler) in &self.subcommands.0 {
|
||||
let mut base = if let Some(cli) = &self.subcommands.0.as_ref().and_then(|h| h.cli()) {
|
||||
cli.cli_command().subcommand_required(false)
|
||||
} else {
|
||||
Params::command().subcommand_required(true)
|
||||
};
|
||||
for (name, handler) in &self.subcommands.1 {
|
||||
match (name, handler.cli()) {
|
||||
(Name(Some(name)), Some(cli)) => {
|
||||
(Name(name), Some(cli)) => {
|
||||
base = base.subcommand(cli.cli_command().name(name));
|
||||
}
|
||||
(Name(None), Some(_)) => {
|
||||
base = base.subcommand_required(false);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -239,13 +300,14 @@ where
|
||||
&self,
|
||||
matches: &ArgMatches,
|
||||
) -> Result<(VecDeque<&'static str>, Value), clap::Error> {
|
||||
let root_params = imbl_value::to_value(&Params::from_arg_matches(matches)?)
|
||||
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?;
|
||||
let (name, matches) = match matches.subcommand() {
|
||||
Some((name, matches)) => (Some(name), matches),
|
||||
None => (None, matches),
|
||||
};
|
||||
if let Some((Name(Some(name)), cli)) = self
|
||||
if let Some(name) = name {
|
||||
let root_params = imbl_value::to_value(&Params::from_arg_matches(matches)?)
|
||||
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?;
|
||||
if let Some((Name(name), cli)) = self
|
||||
.subcommands
|
||||
.get(name)
|
||||
.and_then(|(n, h)| h.cli().map(|c| (n, c)))
|
||||
@@ -255,12 +317,24 @@ where
|
||||
|
||||
Ok((
|
||||
method,
|
||||
combine(root_params, params)
|
||||
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e))?,
|
||||
combine(root_params, params).map_err(|e| {
|
||||
clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e)
|
||||
})?,
|
||||
))
|
||||
} else {
|
||||
Ok((VecDeque::new(), root_params))
|
||||
}
|
||||
} else {
|
||||
if let Some(cli) = self.subcommands.get_root().and_then(|h| h.cli()) {
|
||||
let (method, params) = cli.cli_parse(matches)?;
|
||||
|
||||
Ok((method, params))
|
||||
} else {
|
||||
let root_params = imbl_value::to_value(&Params::from_arg_matches(matches)?)
|
||||
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?;
|
||||
Ok((VecDeque::new(), root_params))
|
||||
}
|
||||
}
|
||||
}
|
||||
fn cli_display(
|
||||
&self,
|
||||
@@ -277,7 +351,6 @@ where
|
||||
let cmd = method.pop_front();
|
||||
if let Some(cmd) = cmd {
|
||||
parent_method.push_back(cmd);
|
||||
}
|
||||
if let Some((_, cli)) = self
|
||||
.subcommands
|
||||
.get(cmd)
|
||||
@@ -296,5 +369,21 @@ where
|
||||
} else {
|
||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||
}
|
||||
} else {
|
||||
if let Some(cli) = self.subcommands.get_root().and_then(|h| h.cli()) {
|
||||
cli.cli_display(
|
||||
HandleAnyArgs {
|
||||
context,
|
||||
parent_method,
|
||||
method,
|
||||
params: raw_params,
|
||||
inherited: inherited_params,
|
||||
},
|
||||
result,
|
||||
)
|
||||
} else {
|
||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user