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> {
|
pub fn run(self, args: impl IntoIterator<Item = OsString>) -> Result<(), RpcError> {
|
||||||
let mut cmd = Config::command();
|
let mut cmd = Config::command();
|
||||||
for (name, handler) in &self.root_handler.subcommands.0 {
|
for (name, handler) in &self.root_handler.subcommands.1 {
|
||||||
if let (Name(Some(name)), Some(cli)) = (name, handler.cli()) {
|
if let (Name(name), Some(cli)) = (name, handler.cli()) {
|
||||||
cmd = cmd.subcommand(cli.cli_command().name(name));
|
cmd = cmd.subcommand(cli.cli_command().name(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,32 +14,52 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub(crate) struct Name(pub(crate) Option<&'static str>);
|
pub(crate) struct Name(pub(crate) &'static str);
|
||||||
impl<'a> std::borrow::Borrow<Option<&'a str>> for Name {
|
impl<'a> std::borrow::Borrow<&'a str> for Name {
|
||||||
fn borrow(&self) -> &Option<&'a str> {
|
fn borrow(&self) -> &&'a str {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SubcommandMap<Context, Inherited>(
|
pub(crate) struct SubcommandMap<Context, Params, InheritedParams>(
|
||||||
pub(crate) OrdMap<Name, DynHandler<Context, Inherited>>,
|
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 {
|
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 {
|
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> {
|
impl<Context, Params, InheritedParams> SubcommandMap<Context, Params, InheritedParams> {
|
||||||
fn insert(&mut self, name: Option<&'static str>, handler: DynHandler<Context, Inherited>) {
|
fn set_root(&mut self, handler: DynHandler<Context, InheritedParams>) {
|
||||||
self.0.insert(Name(name), handler);
|
self.0 = Some(handler);
|
||||||
}
|
}
|
||||||
fn get<'a>(&'a self, name: Option<&str>) -> Option<(Name, &'a DynHandler<Context, Inherited>)> {
|
fn get_root<'a>(&'a self) -> Option<&'a DynHandler<Context, InheritedParams>> {
|
||||||
if let Some((name, handler)) = self.0.get_key_value(&name) {
|
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))
|
Some((*name, handler))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -49,14 +69,14 @@ impl<Context, Inherited> SubcommandMap<Context, Inherited> {
|
|||||||
|
|
||||||
pub struct ParentHandler<Context, Params = Empty, InheritedParams = Empty> {
|
pub struct ParentHandler<Context, Params = Empty, InheritedParams = Empty> {
|
||||||
_phantom: PhantomData<Context>,
|
_phantom: PhantomData<Context>,
|
||||||
pub(crate) subcommands: SubcommandMap<Context, Flat<Params, InheritedParams>>,
|
pub(crate) subcommands: SubcommandMap<Context, Params, InheritedParams>,
|
||||||
metadata: OrdMap<&'static str, Value>,
|
metadata: OrdMap<&'static str, Value>,
|
||||||
}
|
}
|
||||||
impl<Context, Params, InheritedParams> ParentHandler<Context, Params, InheritedParams> {
|
impl<Context, Params, InheritedParams> ParentHandler<Context, Params, InheritedParams> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
_phantom: PhantomData::new(),
|
_phantom: PhantomData::new(),
|
||||||
subcommands: SubcommandMap(OrdMap::new()),
|
subcommands: SubcommandMap(None, OrdMap::new()),
|
||||||
metadata: 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
|
pub fn root_handler<C: crate::Context, H>(mut self, handler: H) -> Self
|
||||||
where
|
where
|
||||||
WithContext<C, H>: Handler<Flat<Params, InheritedParams>>,
|
WithContext<C, H>: Handler<InheritedParams>,
|
||||||
<WithContext<C, H> as Handler<Flat<Params, InheritedParams>>>::H:
|
<WithContext<C, H> as Handler<InheritedParams>>::H: HandlerTypes<Params = Params>,
|
||||||
HandlerTypes<Params = Empty>,
|
|
||||||
{
|
{
|
||||||
if let Some(h) = DynHandler::new(handler) {
|
if let Some(h) = DynHandler::new(handler) {
|
||||||
self.subcommands.insert(None, h);
|
self.subcommands.set_root(h);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -142,17 +161,29 @@ where
|
|||||||
let cmd = method.pop_front();
|
let cmd = method.pop_front();
|
||||||
if let Some(cmd) = cmd {
|
if let Some(cmd) = cmd {
|
||||||
parent_method.push_back(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_sync(HandleAnyArgs {
|
||||||
sub_handler.handle_sync(HandleAnyArgs {
|
context,
|
||||||
context,
|
parent_method,
|
||||||
parent_method,
|
method,
|
||||||
method,
|
params: raw_params,
|
||||||
params: raw_params,
|
inherited: Flat(params, inherited_params),
|
||||||
inherited: Flat(params, inherited_params),
|
})
|
||||||
})
|
} else {
|
||||||
|
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
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(
|
async fn handle_async(
|
||||||
@@ -169,27 +200,49 @@ where
|
|||||||
let cmd = method.pop_front();
|
let cmd = method.pop_front();
|
||||||
if let Some(cmd) = cmd {
|
if let Some(cmd) = cmd {
|
||||||
parent_method.push_back(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
|
||||||
sub_handler
|
.handle_async(HandleAnyArgs {
|
||||||
.handle_async(HandleAnyArgs {
|
context,
|
||||||
context,
|
parent_method,
|
||||||
parent_method,
|
method,
|
||||||
method,
|
params: raw_params,
|
||||||
params: raw_params,
|
inherited: Flat(params, inherited_params),
|
||||||
inherited: Flat(params, inherited_params),
|
})
|
||||||
})
|
.await
|
||||||
.await
|
} else {
|
||||||
|
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
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> {
|
fn metadata(&self, mut method: VecDeque<&'static str>) -> OrdMap<&'static str, Value> {
|
||||||
let metadata = self.metadata.clone();
|
let metadata = self.metadata.clone();
|
||||||
if let Some((_, handler)) = self.subcommands.get(method.pop_front()) {
|
if let Some(cmd) = method.pop_front() {
|
||||||
handler.metadata(method).union(metadata)
|
if let Some((_, handler)) = self.subcommands.get(cmd) {
|
||||||
|
handler.metadata(method).union(metadata)
|
||||||
|
} else {
|
||||||
|
metadata
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
metadata
|
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>> {
|
fn method_from_dots(&self, method: &str) -> Option<VecDeque<&'static str>> {
|
||||||
@@ -201,15 +254,22 @@ where
|
|||||||
.map(|(head, tail)| (Some(head), Some(tail)))
|
.map(|(head, tail)| (Some(head), Some(tail)))
|
||||||
.unwrap_or((Some(method), None))
|
.unwrap_or((Some(method), None))
|
||||||
};
|
};
|
||||||
let (Name(name), h) = self.subcommands.get(head)?;
|
if let Some(head) = head {
|
||||||
let mut res = VecDeque::new();
|
let (Name(name), h) = self.subcommands.get(head)?;
|
||||||
if let Some(name) = name {
|
let mut res = VecDeque::new();
|
||||||
res.push_back(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)
|
||||||
}
|
}
|
||||||
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,
|
InheritedParams: Serialize + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn cli_command(&self) -> Command {
|
fn cli_command(&self) -> Command {
|
||||||
let mut base = Params::command().subcommand_required(true);
|
let mut base = if let Some(cli) = &self.subcommands.0.as_ref().and_then(|h| h.cli()) {
|
||||||
for (name, handler) in &self.subcommands.0 {
|
cli.cli_command().subcommand_required(false)
|
||||||
|
} else {
|
||||||
|
Params::command().subcommand_required(true)
|
||||||
|
};
|
||||||
|
for (name, handler) in &self.subcommands.1 {
|
||||||
match (name, handler.cli()) {
|
match (name, handler.cli()) {
|
||||||
(Name(Some(name)), Some(cli)) => {
|
(Name(name), Some(cli)) => {
|
||||||
base = base.subcommand(cli.cli_command().name(name));
|
base = base.subcommand(cli.cli_command().name(name));
|
||||||
}
|
}
|
||||||
(Name(None), Some(_)) => {
|
|
||||||
base = base.subcommand_required(false);
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,27 +300,40 @@ where
|
|||||||
&self,
|
&self,
|
||||||
matches: &ArgMatches,
|
matches: &ArgMatches,
|
||||||
) -> Result<(VecDeque<&'static str>, Value), clap::Error> {
|
) -> 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() {
|
let (name, matches) = match matches.subcommand() {
|
||||||
Some((name, matches)) => (Some(name), matches),
|
Some((name, matches)) => (Some(name), matches),
|
||||||
None => (None, matches),
|
None => (None, matches),
|
||||||
};
|
};
|
||||||
if let Some((Name(Some(name)), cli)) = self
|
if let Some(name) = name {
|
||||||
.subcommands
|
let root_params = imbl_value::to_value(&Params::from_arg_matches(matches)?)
|
||||||
.get(name)
|
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?;
|
||||||
.and_then(|(n, h)| h.cli().map(|c| (n, c)))
|
if let Some((Name(name), cli)) = self
|
||||||
{
|
.subcommands
|
||||||
let (mut method, params) = cli.cli_parse(matches)?;
|
.get(name)
|
||||||
method.push_front(name);
|
.and_then(|(n, h)| h.cli().map(|c| (n, c)))
|
||||||
|
{
|
||||||
|
let (mut method, params) = cli.cli_parse(matches)?;
|
||||||
|
method.push_front(name);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
method,
|
method,
|
||||||
combine(root_params, params)
|
combine(root_params, params).map_err(|e| {
|
||||||
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e))?,
|
clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e)
|
||||||
))
|
})?,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok((VecDeque::new(), root_params))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok((VecDeque::new(), root_params))
|
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(
|
fn cli_display(
|
||||||
@@ -277,24 +351,39 @@ where
|
|||||||
let cmd = method.pop_front();
|
let cmd = method.pop_front();
|
||||||
if let Some(cmd) = cmd {
|
if let Some(cmd) = cmd {
|
||||||
parent_method.push_back(cmd);
|
parent_method.push_back(cmd);
|
||||||
}
|
if let Some((_, cli)) = self
|
||||||
if let Some((_, cli)) = self
|
.subcommands
|
||||||
.subcommands
|
.get(cmd)
|
||||||
.get(cmd)
|
.and_then(|(n, h)| h.cli().map(|c| (n, c)))
|
||||||
.and_then(|(n, h)| h.cli().map(|c| (n, c)))
|
{
|
||||||
{
|
cli.cli_display(
|
||||||
cli.cli_display(
|
HandleAnyArgs {
|
||||||
HandleAnyArgs {
|
context,
|
||||||
context,
|
parent_method,
|
||||||
parent_method,
|
method,
|
||||||
method,
|
params: raw_params,
|
||||||
params: raw_params,
|
inherited: Flat(params, inherited_params),
|
||||||
inherited: Flat(params, inherited_params),
|
},
|
||||||
},
|
result,
|
||||||
result,
|
)
|
||||||
)
|
} else {
|
||||||
|
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
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