use core::iter;
use debate_parser::Arg;
use crate::{errors, help::HelpRequest, parameter};
pub trait SubcommandVisitor {
type Output;
fn visit_subcommand(self, subcommand: &SubcommandPath<'_>) -> Self::Output;
}
#[derive(Debug, Clone, Copy)]
pub enum SubcommandPathItem<'a> {
Field(&'a str),
Command(&'a str),
}
#[derive(Debug)]
pub struct SubcommandPath<'a> {
item: SubcommandPathItem<'a>,
prev: Option<&'a SubcommandPath<'a>>,
}
impl<'a> SubcommandPath<'a> {
pub const fn new(item: SubcommandPathItem<'a>) -> SubcommandPath<'a> {
Self { item, prev: None }
}
pub const fn chain(&'a self, item: SubcommandPathItem<'a>) -> Self {
Self {
item,
prev: Some(self),
}
}
pub fn iter<'s>(&'s self) -> impl Iterator<Item = &'s SubcommandPathItem<'a>> {
iter::successors(Some(self), |current| current.prev).map(|current| ¤t.item)
}
}
#[doc(hidden)]
pub struct SubcommandPathVisitorWithItem<'a, V> {
item: SubcommandPathItem<'a>,
visitor: V,
}
impl<'a, V: SubcommandVisitor> SubcommandPathVisitorWithItem<'a, V> {
#[inline]
#[must_use]
pub const fn new(item: SubcommandPathItem<'a>, visitor: V) -> Self {
Self { item, visitor }
}
#[inline]
#[must_use]
pub fn into_inner(self) -> V {
self.visitor
}
pub fn call(self) -> V::Output {
self.visitor
.visit_subcommand(&SubcommandPath::new(self.item))
}
}
impl<V: SubcommandVisitor> SubcommandVisitor for SubcommandPathVisitorWithItem<'_, V> {
type Output = V::Output;
#[inline]
fn visit_subcommand(self, subcommand: &SubcommandPath<'_>) -> Self::Output {
let wrapped = subcommand.chain(self.item);
self.visitor.visit_subcommand(&wrapped)
}
}
pub trait State<'arg> {
fn add_positional<E>(&mut self, argument: &'arg Arg) -> Result<(), E>
where
E: Error<'arg, ()>;
fn add_long_argument<E>(&mut self, option: &'arg Arg, argument: &'arg Arg) -> Result<(), E>
where
E: Error<'arg, ()>;
fn add_long<A, E>(&mut self, option: &'arg Arg, argument: A) -> Result<(), E>
where
A: parameter::ArgAccess<'arg>,
E: Error<'arg, A>;
fn add_short<A, E>(&mut self, option: u8, argument: A) -> Result<(), E>
where
A: parameter::ArgAccess<'arg>,
E: Error<'arg, A>;
fn get_subcommand_path<V>(&self, visitor: V) -> Result<V::Output, V>
where
V: SubcommandVisitor,
{
Err(visitor)
}
}
pub trait Error<'arg, Arg>: Sized {
type ParameterError: parameter::Error<'arg>;
type FlagList: errors::FlagsList<'static>;
fn parameter(field: &'static str, error: Self::ParameterError) -> Self;
fn unrecognized(argument: Arg) -> Self;
fn flattened(field: &'static str, error: Self) -> Self;
fn unknown_subcommand(expected: &'static [&'static str]) -> Self;
fn wrong_subcommand_for_argument(
subcommand: &'static str,
allowed: &'static [&'static str],
) -> Self;
fn conflicts_with_flags(flags: Self::FlagList) -> Self;
fn help_requested(request: HelpRequest) -> Self;
}