Skip to content

Commit a7f7bb2

Browse files
committed
Use u8 for internal verbosity level calculation
This avoids integer overflow / underflow errors when calculating the verbosity level. Prior to this change, constructing a `Verbosity` with either parameter equal to `u8::MAX` would result in incorrect verbosity level calculation.
1 parent 7f435cd commit a7f7bb2

File tree

1 file changed

+24
-52
lines changed

1 file changed

+24
-52
lines changed

src/lib.rs

+24-52
Original file line numberDiff line numberDiff line change
@@ -126,30 +126,32 @@ impl<L: LogLevel> Verbosity<L> {
126126
self.log_level().is_none()
127127
}
128128

129-
fn verbosity(&self) -> i8 {
130-
level_value(L::default()) - (self.quiet as i8) + (self.verbose as i8)
129+
fn verbosity(&self) -> u8 {
130+
let default_verbosity = level_value(L::default());
131+
let verbosity = default_verbosity as i16 - self.quiet as i16 + self.verbose as i16;
132+
verbosity.clamp(0, u8::MAX as i16) as u8
131133
}
132134
}
133135

134-
fn level_value(level: Option<Level>) -> i8 {
136+
fn level_value(level: Option<Level>) -> u8 {
135137
match level {
136-
None => -1,
137-
Some(Level::Error) => 0,
138-
Some(Level::Warn) => 1,
139-
Some(Level::Info) => 2,
140-
Some(Level::Debug) => 3,
141-
Some(Level::Trace) => 4,
138+
None => 0,
139+
Some(Level::Error) => 1,
140+
Some(Level::Warn) => 2,
141+
Some(Level::Info) => 3,
142+
Some(Level::Debug) => 4,
143+
Some(Level::Trace) => 5,
142144
}
143145
}
144146

145-
fn level_enum(verbosity: i8) -> Option<Level> {
147+
fn level_enum(verbosity: u8) -> Option<Level> {
146148
match verbosity {
147-
i8::MIN..=-1 => None,
148-
0 => Some(Level::Error),
149-
1 => Some(Level::Warn),
150-
2 => Some(Level::Info),
151-
3 => Some(Level::Debug),
152-
4..=i8::MAX => Some(Level::Trace),
149+
0 => None,
150+
1 => Some(Level::Error),
151+
2 => Some(Level::Warn),
152+
3 => Some(Level::Info),
153+
4 => Some(Level::Debug),
154+
5..=u8::MAX => Some(Level::Trace),
153155
}
154156
}
155157

@@ -246,8 +248,10 @@ mod test {
246248
(3, 0, Some(Level::Debug), LevelFilter::Debug),
247249
(4, 0, Some(Level::Trace), LevelFilter::Trace),
248250
(5, 0, Some(Level::Trace), LevelFilter::Trace),
251+
(255, 0, Some(Level::Trace), LevelFilter::Trace),
249252
(0, 1, None, LevelFilter::Off),
250253
(0, 2, None, LevelFilter::Off),
254+
(0, 255, None, LevelFilter::Off),
251255
(255, 255, Some(Level::Error), LevelFilter::Error),
252256
];
253257

@@ -266,18 +270,6 @@ mod test {
266270
}
267271
}
268272

269-
/// These are characterization tests that show the current behavior
270-
#[test]
271-
fn verbosity_error_level_max_incorrect() {
272-
let v: Verbosity<ErrorLevel> = Verbosity::new(255, 0);
273-
assert_eq!(v.log_level(), None); // Should be Some(Level::Trace)
274-
assert_eq!(v.log_level_filter(), LevelFilter::Off); // Should be LevelFilter::Trace
275-
276-
let v: Verbosity<ErrorLevel> = Verbosity::new(0, 255);
277-
assert_eq!(v.log_level(), Some(Level::Warn)); // Should be None
278-
assert_eq!(v.log_level_filter(), LevelFilter::Warn); // Should be LevelFilter::Off
279-
}
280-
281273
#[test]
282274
fn verbosity_warn_level() {
283275
let tests = [
@@ -287,9 +279,11 @@ mod test {
287279
(2, 0, Some(Level::Debug), LevelFilter::Debug),
288280
(3, 0, Some(Level::Trace), LevelFilter::Trace),
289281
(4, 0, Some(Level::Trace), LevelFilter::Trace),
282+
(255, 0, Some(Level::Trace), LevelFilter::Trace),
290283
(0, 1, Some(Level::Error), LevelFilter::Error),
291284
(0, 2, None, LevelFilter::Off),
292285
(0, 3, None, LevelFilter::Off),
286+
(0, 255, None, LevelFilter::Off),
293287
(255, 255, Some(Level::Warn), LevelFilter::Warn),
294288
];
295289

@@ -308,18 +302,6 @@ mod test {
308302
}
309303
}
310304

311-
/// These are characterization tests that show the current behavior
312-
#[test]
313-
fn verbosity_warn_level_max_incorrect() {
314-
let v: Verbosity<WarnLevel> = Verbosity::new(255, 0);
315-
assert_eq!(v.log_level(), Some(Level::Error)); // Should be Some(Level::Trace)
316-
assert_eq!(v.log_level_filter(), LevelFilter::Error); // Should be LevelFilter::Trace
317-
318-
let v: Verbosity<WarnLevel> = Verbosity::new(0, 255);
319-
assert_eq!(v.log_level(), Some(Level::Info)); // Should be None
320-
assert_eq!(v.log_level_filter(), LevelFilter::Info); // Should be LevelFilter::Off
321-
}
322-
323305
#[test]
324306
fn verbosity_info_level() {
325307
let tests = [
@@ -328,10 +310,12 @@ mod test {
328310
(1, 0, Some(Level::Debug), LevelFilter::Debug),
329311
(2, 0, Some(Level::Trace), LevelFilter::Trace),
330312
(3, 0, Some(Level::Trace), LevelFilter::Trace),
313+
(255, 0, Some(Level::Trace), LevelFilter::Trace),
331314
(0, 1, Some(Level::Warn), LevelFilter::Warn),
332315
(0, 2, Some(Level::Error), LevelFilter::Error),
333316
(0, 3, None, LevelFilter::Off),
334317
(0, 4, None, LevelFilter::Off),
318+
(0, 255, None, LevelFilter::Off),
335319
(255, 255, Some(Level::Info), LevelFilter::Info),
336320
];
337321

@@ -349,16 +333,4 @@ mod test {
349333
);
350334
}
351335
}
352-
353-
/// These are characterization tests that show the current behavior
354-
#[test]
355-
fn verbosity_info_level_max_incorrect() {
356-
let v: Verbosity<InfoLevel> = Verbosity::new(255, 0);
357-
assert_eq!(v.log_level(), Some(Level::Warn)); // Should be Some(Level::Trace)
358-
assert_eq!(v.log_level_filter(), LevelFilter::Warn); // Should be LevelFilter::Trace
359-
360-
let v: Verbosity<InfoLevel> = Verbosity::new(0, 255);
361-
assert_eq!(v.log_level(), Some(Level::Debug)); // Should be None
362-
assert_eq!(v.log_level_filter(), LevelFilter::Debug); // Should be LevelFilter::Off
363-
}
364336
}

0 commit comments

Comments
 (0)