mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust/utils: Add 'ExitCodeTrait' and an macro that implements the trait
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>
This commit is contained in:
committed by
Jan Höppner
parent
ea297ecf84
commit
d73f4dc22a
171
rust/utils/src/exit_code.rs
Normal file
171
rust/utils/src/exit_code.rs
Normal file
@@ -0,0 +1,171 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
//!
|
||||
//! Copyright IBM Corp. 2023, 2024
|
||||
mod cli;
|
||||
mod exit_code;
|
||||
mod file;
|
||||
mod hexslice;
|
||||
mod log;
|
||||
@@ -16,6 +17,7 @@ pub use crate::{
|
||||
get_reader_from_cli_file_arg, get_writer_from_cli_file_arg, print_cli_error, print_error,
|
||||
CertificateOptions, DeprecatedVerbosityOptions, VerbosityOptions, STDIN, STDOUT,
|
||||
},
|
||||
exit_code::{docstring, ExitCodeDoc, ExitCodeTrait, ExitCodeVariantDoc},
|
||||
file::{AtomicFile, AtomicFileOperation},
|
||||
hexslice::HexSlice,
|
||||
log::PvLogger,
|
||||
|
||||
Reference in New Issue
Block a user