#![cfg_attr(not(feature = "default"), allow(unused))]
use std::fmt;
#[cfg(not(feature = "help"))]
use std::marker::PhantomData;
use crate::util::{split_once, split_sep_many, split_terminator};
#[derive(Debug)]
pub struct RawSubcommandInfo<A: ?Sized = [&'static str]> {
#[cfg(feature = "help")]
subcommands: &'static str,
#[cfg(feature = "help")]
cmd_docs: A,
#[cfg(not(feature = "help"))]
_marker: PhantomData<A>,
}
impl RawSubcommandInfo {
pub(crate) const EMPTY_REF: &Self = &Self::new("", []);
#[cfg(feature = "help")]
pub const fn new<const N: usize>(
subcommands: &'static str,
cmd_docs: [&'static str; N],
) -> RawSubcommandInfo<[&'static str; N]> {
RawSubcommandInfo { subcommands, cmd_docs }
}
#[cfg(not(feature = "help"))]
pub const fn new<const N: usize>(
_subcommands: &'static str,
_cmd_docs: [&'static str; N],
) -> Self {
Self { _marker: PhantomData }
}
}
type FmtWriter = fn(w: &mut dyn fmt::Write, what: u8);
const fn fmt_noop(_w: &mut dyn fmt::Write, _what: u8) {}
pub(crate) const FMT_UNNAMED: u8 = 0;
pub(crate) const FMT_NAMED: u8 = 1;
pub(crate) const FMT_USAGE_UNNAMED: u8 = 2;
pub(crate) const FMT_USAGE_NAMED: u8 = 3;
#[derive(Debug, Clone, Copy)]
pub struct RawArgsInfoRef(pub &'static RawArgsInfo);
#[derive(Debug)]
pub struct RawArgsInfo<A: ?Sized = [RawArgsInfoRef]> {
descriptions: &'static str,
#[cfg(feature = "help")]
subcmd_optional: bool,
#[cfg(feature = "help")]
has_optional_named: bool,
#[cfg(feature = "help")]
subcmd_info: Option<&'static RawSubcommandInfo>,
#[cfg(feature = "help")]
cmd_doc: &'static str,
#[cfg(feature = "help")]
fmt_help: FmtWriter,
flattened: A,
}
impl RawArgsInfo {
pub(crate) const EMPTY_REF: &'static Self =
&RawArgsInfo::new(false, false, None, "", "", fmt_noop, []);
pub const fn new<const N: usize>(
subcmd_optional: bool,
mut has_optional_named: bool,
subcmd_info: Option<&'static RawSubcommandInfo>,
cmd_doc: &'static str,
descriptions: &'static str,
fmt_help: FmtWriter,
flattened: [RawArgsInfoRef; N],
) -> RawArgsInfo<[RawArgsInfoRef; N]> {
#[cfg(feature = "help")]
{
let len = flattened.len();
let mut i = 0usize;
while i < len {
let inner = flattened[i];
has_optional_named |= inner.0.has_optional_named;
i += 1;
}
}
RawArgsInfo {
descriptions,
#[cfg(feature = "help")]
subcmd_optional,
#[cfg(feature = "help")]
has_optional_named,
#[cfg(feature = "help")]
subcmd_info,
#[cfg(feature = "help")]
cmd_doc,
#[cfg(feature = "help")]
fmt_help,
flattened,
}
}
pub const fn raw_cmd_docs(&self) -> &str {
#[cfg(feature = "help")]
{
self.cmd_doc
}
#[cfg(not(feature = "help"))]
{
""
}
}
pub(crate) fn get_description(&self, mut idx: u8) -> Option<&'static str> {
let mut desc = self.descriptions;
while let Some((lhs, rhs)) = split_once(desc, b'\0') {
if idx == 0 {
return Some(lhs);
}
idx -= 1;
desc = rhs;
}
for child in &self.flattened {
if let Some(s) = child.0.get_description(idx) {
return Some(s);
}
}
None
}
#[cfg(feature = "help")]
pub(crate) fn has_optional_named(&self) -> bool {
self.has_optional_named
}
#[cfg(feature = "help")]
pub(crate) fn fmt_help(&self, w: &mut dyn fmt::Write, what: u8) {
(self.fmt_help)(w, what);
for f in &self.flattened {
f.0.fmt_help(w, what);
}
}
#[cfg(feature = "help")]
pub(crate) fn doc(&self) -> CommandDoc {
let [long_about, after_long_help] = split_sep_many(self.cmd_doc, b'\0').unwrap_or([""; 2]);
CommandDoc { long_about, after_long_help }
}
#[cfg(feature = "help")]
pub(crate) fn subcommands(
&self,
) -> Option<impl Iterator<Item = (&'static str, &'static str)> + Clone> {
let subcmd = self.subcmd_info?;
Some(split_terminator(subcmd.subcommands, b'\0').zip(
subcmd.cmd_docs.iter().map(|raw_doc| split_once(raw_doc, b'\0').unwrap_or(("", "")).0),
))
}
#[cfg(feature = "help")]
pub(crate) fn subcommand_optional(&self) -> bool {
self.subcmd_optional
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CommandDoc {
pub(crate) long_about: &'static str,
pub(crate) after_long_help: &'static str,
}