Skip to main content

eth_valkyoth_codec/
exact.rs

1use core::cmp::Ordering;
2
3use crate::DecodeError;
4
5/// Ensures a decoder consumed the whole input.
6pub fn require_exact_consumption(consumed: usize, input_len: usize) -> Result<(), DecodeError> {
7    match consumed.cmp(&input_len) {
8        Ordering::Equal => Ok(()),
9        Ordering::Less => Err(DecodeError::TrailingBytes),
10        Ordering::Greater => Err(DecodeError::DecoderOverread),
11    }
12}
13
14/// Adds two decoded lengths and rejects integer overflow.
15pub fn checked_len_add(left: usize, right: usize) -> Result<usize, DecodeError> {
16    left.checked_add(right).ok_or(DecodeError::LengthOverflow)
17}
18
19/// Computes the end offset for a decoded range and rejects overflow.
20pub fn checked_range_end(offset: usize, len: usize) -> Result<usize, DecodeError> {
21    checked_len_add(offset, len)
22}
23
24/// Ensures a decoded range is inside an input buffer and returns its end.
25pub fn require_range_in_bounds(
26    offset: usize,
27    len: usize,
28    input_len: usize,
29) -> Result<usize, DecodeError> {
30    let end = checked_range_end(offset, len)?;
31    if offset > input_len || end > input_len {
32        return Err(DecodeError::OffsetOutOfBounds);
33    }
34    Ok(end)
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn detects_trailing_bytes() {
43        assert_eq!(
44            require_exact_consumption(1, 2),
45            Err(DecodeError::TrailingBytes)
46        );
47    }
48
49    #[test]
50    fn detects_decoder_overread() {
51        assert_eq!(
52            require_exact_consumption(3, 2),
53            Err(DecodeError::DecoderOverread)
54        );
55    }
56
57    #[test]
58    fn checked_len_add_rejects_overflow() {
59        assert_eq!(
60            checked_len_add(usize::MAX, 1),
61            Err(DecodeError::LengthOverflow)
62        );
63    }
64
65    #[test]
66    fn checked_range_end_rejects_overflow() {
67        assert_eq!(
68            checked_range_end(usize::MAX, 1),
69            Err(DecodeError::LengthOverflow)
70        );
71    }
72
73    #[test]
74    fn require_range_in_bounds_accepts_valid_range() {
75        assert_eq!(require_range_in_bounds(2, 3, 5), Ok(5));
76    }
77
78    #[test]
79    fn require_range_in_bounds_rejects_end_beyond_input() {
80        assert_eq!(
81            require_range_in_bounds(2, 4, 5),
82            Err(DecodeError::OffsetOutOfBounds)
83        );
84    }
85
86    #[test]
87    fn require_range_in_bounds_rejects_offset_beyond_input() {
88        assert_eq!(
89            require_range_in_bounds(6, 0, 5),
90            Err(DecodeError::OffsetOutOfBounds)
91        );
92    }
93}