schema_registry_cli/settings/
verbosity.rs1use clap::{ArgAction, Args};
2
3#[derive(Debug, Clone, Copy, Default, Args)]
12pub struct Verbosity {
13 #[arg(long, short='v', action= ArgAction::Count, global = true)]
15 verbose: u8,
16
17 #[arg(long, short='q', action= ArgAction::Count, global = true)]
19 quiet: u8,
20}
21
22impl From<Verbosity> for i16 {
23 fn from(value: Verbosity) -> Self {
24 let result = i16::from(value.verbose) - i16::from(value.quiet);
25 result.clamp(-2, 3)
26 }
27}
28
29impl PartialEq for Verbosity {
30 fn eq(&self, other: &Self) -> bool {
31 i16::from(*self) == i16::from(*other)
32 }
33}
34impl Eq for Verbosity {}
35
36impl Ord for Verbosity {
37 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
38 i16::from(*self).cmp(&i16::from(*other))
39 }
40}
41impl PartialOrd for Verbosity {
42 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
43 Some(self.cmp(other))
44 }
45}
46
47impl Verbosity {
48 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
49 const fn new(level: i16) -> Self {
50 if level == 0 {
51 Self {
52 verbose: 0,
53 quiet: 0,
54 }
55 } else if level > 0 {
56 Self {
57 verbose: level as u8,
58 quiet: 0,
59 }
60 } else {
61 Self {
62 verbose: 0,
63 quiet: level.unsigned_abs() as u8,
64 }
65 }
66 }
67
68 pub const OFF: Verbosity = Verbosity::new(-2);
70
71 pub const ERROR: Verbosity = Verbosity::new(-1);
73
74 pub const WARN: Verbosity = Verbosity::new(0);
76
77 pub const INFO: Verbosity = Verbosity::new(1);
79
80 pub const DEBUG: Verbosity = Verbosity::new(2);
82
83 pub const TRACE: Verbosity = Verbosity::new(3);
85}
86
87#[cfg(test)]
88mod tests {
89 use assert2::check;
90 use clap::Parser;
91
92 use super::*;
93
94 #[derive(Debug, Parser)]
95 struct JustVerbosity {
96 #[clap(flatten)]
97 verbosity: Verbosity,
98 }
99
100 #[rstest::rstest]
101 #[case::off(Verbosity::OFF, -2)]
102 #[case::error(Verbosity::ERROR, -1)]
103 #[case::warn(Verbosity::WARN, 0)]
104 #[case::info(Verbosity::INFO, 1)]
105 #[case::debug(Verbosity::DEBUG, 2)]
106 #[case::trace(Verbosity::TRACE, 3)]
107 fn should_provide_number(#[case] verbosity: Verbosity, #[case] num: i16) {
108 let result = i16::from(verbosity);
109 check!(result == num);
110 let result = Verbosity::new(num);
111 check!(result == verbosity);
112 }
113
114 #[rstest::rstest]
115 #[case::trace(&["bin", "-vvvvvvvvvvv"], Verbosity::TRACE)]
116 #[case::trace(&["bin", "-vvv"], Verbosity::TRACE)]
117 #[case::debug(&["bin", "-vv"], Verbosity::DEBUG)]
118 #[case::info(&["bin", "-v"], Verbosity::INFO)]
119 #[case::warn(&["bin"], Verbosity::WARN)]
120 #[case::error(&["bin", "-q"], Verbosity::ERROR)]
121 #[case::off(&["bin", "-qq"], Verbosity::OFF)]
122 #[case::off(&["bin", "-qqqqqqqq"], Verbosity::OFF)]
123 fn should_parse_verbosity(#[case] args: &[&str], #[case] expected: Verbosity) {
124 let result = JustVerbosity::parse_from(args);
125 check!(result.verbosity == expected);
126 }
127
128 #[test]
129 fn should_be_sorted() {
130 let v = &[
131 Verbosity::OFF,
132 Verbosity::ERROR,
133 Verbosity::WARN,
134 Verbosity::INFO,
135 Verbosity::DEBUG,
136 Verbosity::TRACE,
137 ];
138
139 for win in v.windows(2) {
140 check!(win[0] < win[1]);
141 check!(i16::from(win[0]) < i16::from(win[1]));
142 }
143 }
144}