mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
A manpage auto-generation tool can use this trait to get the exit codes and their documentation of a program. Reviewed-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
172 lines
5.3 KiB
Rust
172 lines
5.3 KiB
Rust
// SPDX-License-Identifier: MIT
|
|
//
|
|
// Copyright IBM Corp. 2024
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct ExitCodeVariantDoc {
|
|
pub name: String,
|
|
pub value: String,
|
|
pub doc: String,
|
|
}
|
|
|
|
impl ExitCodeVariantDoc {
|
|
pub fn new<N, V, D>(name: N, value: V, doc: D) -> Self
|
|
where
|
|
N: AsRef<str>,
|
|
V: AsRef<str>,
|
|
D: AsRef<str>,
|
|
{
|
|
Self {
|
|
name: name.as_ref().to_string(),
|
|
value: value.as_ref().to_string(),
|
|
doc: doc.as_ref().to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct ExitCodeDoc {
|
|
pub doc: Option<String>,
|
|
pub variants: Vec<ExitCodeVariantDoc>,
|
|
}
|
|
|
|
pub trait ExitCodeTrait {
|
|
fn exit_code_doc() -> ExitCodeDoc;
|
|
}
|
|
|
|
pub fn docstring(attr: &str) -> Option<String> {
|
|
if !attr.starts_with("doc = r\"") {
|
|
return None;
|
|
}
|
|
let mut doc = attr
|
|
.strip_prefix("doc = r\"")
|
|
.unwrap()
|
|
.strip_suffix("\"")
|
|
.unwrap()
|
|
.to_string();
|
|
if doc.starts_with(" ") {
|
|
doc = doc.strip_prefix(" ").unwrap().to_string();
|
|
}
|
|
Some(doc)
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! impl_exitcodetrait {
|
|
($(#[$attr:meta])* $vis:vis enum $name:ident $(<$($gen:ident),*>)? {
|
|
$(
|
|
$(#[$variantattr:meta])+ $variant:ident = $tvalue:literal
|
|
),* $(,)?
|
|
}
|
|
) => {
|
|
$(#[$attr])*
|
|
$vis enum $name $(<$($gen),*>)? {
|
|
$(
|
|
$(#[$variantattr])+ $variant = $tvalue
|
|
),*
|
|
}
|
|
|
|
impl ExitCodeTrait for $(<$($gen),*>)? $name $(<$($gen),*>)? {
|
|
fn exit_code_doc() -> $crate::ExitCodeDoc {
|
|
let enum_doc_vec = [$(stringify!($attr)),*].into_iter().map($crate::docstring).filter_map(std::convert::identity).collect::<Vec<_>>();
|
|
let enum_doc = (!enum_doc_vec.is_empty()).then_some(enum_doc_vec.join("\n"));
|
|
let mut variants = vec![];
|
|
$(
|
|
let name = stringify!($variant).to_string();
|
|
let value = stringify!($tvalue).to_string();
|
|
let docs: Vec<_> = [$(stringify!($variantattr)),+].into_iter().map($crate::docstring).filter_map(std::convert::identity).collect();
|
|
assert!(!docs.is_empty(), "Please add a docstring to enum variant '{name}' of '{}'", stringify!($name));
|
|
variants.push($crate::ExitCodeVariantDoc { name, value, doc: docs.join("\n")});
|
|
)*
|
|
$crate::ExitCodeDoc {
|
|
doc: enum_doc,
|
|
variants,
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{exit_code::ExitCodeDoc, ExitCodeTrait, ExitCodeVariantDoc};
|
|
|
|
#[test]
|
|
fn test_impl_exitcodetrait_with_doc() {
|
|
impl_exitcodetrait!(
|
|
/// Program exit codes
|
|
///
|
|
/// Multiline.
|
|
#[repr(u8)]
|
|
#[allow(unused)]
|
|
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub enum OwnExitCode {
|
|
/// Program finished successfully
|
|
///
|
|
/// Long description.
|
|
Success = 0,
|
|
/// Generic error
|
|
#[default]
|
|
GenericError = 1,
|
|
/// Usage error
|
|
UsageError = 2, // same exit code as used by `Clap` crate
|
|
}
|
|
);
|
|
|
|
assert_eq!(
|
|
OwnExitCode::exit_code_doc(),
|
|
ExitCodeDoc {
|
|
doc: Some("Program exit codes\n\nMultiline.".to_string()),
|
|
variants: vec![
|
|
ExitCodeVariantDoc::new(
|
|
"Success",
|
|
"0",
|
|
"Program finished successfully\n\nLong description."
|
|
),
|
|
ExitCodeVariantDoc::new("GenericError", "1", "Generic error"),
|
|
ExitCodeVariantDoc::new("UsageError", "2", "Usage error")
|
|
]
|
|
}
|
|
);
|
|
|
|
assert_eq!(OwnExitCode::default(), OwnExitCode::GenericError);
|
|
}
|
|
|
|
#[test]
|
|
fn test_impl_exitcodetrait_without_doc() {
|
|
impl_exitcodetrait!(
|
|
#[repr(u8)]
|
|
#[allow(unused)]
|
|
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub enum OwnExitCode {
|
|
/// Program finished successfully
|
|
///
|
|
/// Long description.
|
|
Success = 0,
|
|
/// Generic error
|
|
#[default]
|
|
GenericError = 1,
|
|
/// Usage error
|
|
UsageError = 2, // same exit code as used by `Clap` crate
|
|
}
|
|
);
|
|
|
|
assert_eq!(
|
|
OwnExitCode::exit_code_doc(),
|
|
ExitCodeDoc {
|
|
doc: None,
|
|
variants: vec![
|
|
ExitCodeVariantDoc::new(
|
|
"Success",
|
|
"0",
|
|
"Program finished successfully\n\nLong description."
|
|
),
|
|
ExitCodeVariantDoc::new("GenericError", "1", "Generic error"),
|
|
ExitCodeVariantDoc::new("UsageError", "2", "Usage error")
|
|
]
|
|
}
|
|
);
|
|
|
|
assert_eq!(OwnExitCode::default(), OwnExitCode::GenericError);
|
|
}
|
|
}
|