s2n_codec/decoder/
checked_range.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use core::fmt;
5
6#[derive(Copy, Clone)]
7pub struct CheckedRange {
8    start: usize,
9    end: usize,
10
11    #[cfg(all(debug_assertions, feature = "checked_range_unsafe"))]
12    original_ptr: *const u8,
13}
14
15#[cfg(test)]
16impl bolero::TypeGenerator for CheckedRange {
17    fn generate<D: bolero::Driver>(driver: &mut D) -> Option<Self> {
18        use bolero::ValueGenerator;
19
20        let start = bolero::produce::<usize>().generate(driver)?;
21        let end = (start..).generate(driver)?;
22        Some(CheckedRange::new(start, end, core::ptr::null()))
23    }
24}
25
26impl CheckedRange {
27    #[inline]
28    pub(crate) fn new(start: usize, end: usize, original_ptr: *const u8) -> Self {
29        debug_assert!(
30            end >= start,
31            "end: {end} must be greater than or equal to start: {start}",
32        );
33        #[cfg(not(all(debug_assertions, feature = "checked_range_unsafe")))]
34        let _ = original_ptr;
35
36        Self {
37            start,
38            end,
39            #[cfg(all(debug_assertions, feature = "checked_range_unsafe"))]
40            original_ptr,
41        }
42    }
43
44    #[cfg(feature = "checked_range_unsafe")]
45    #[inline]
46    pub fn get<'a>(&self, slice: &'a [u8]) -> &'a [u8] {
47        unsafe {
48            #[cfg(debug_assertions)]
49            debug_assert_eq!(slice.as_ptr().add(self.start), self.original_ptr);
50
51            slice.get_unchecked(self.start..self.end)
52        }
53    }
54
55    #[cfg(not(feature = "checked_range_unsafe"))]
56    #[inline]
57    pub fn get<'a>(&self, slice: &'a [u8]) -> &'a [u8] {
58        &slice[self.start..self.end]
59    }
60
61    #[cfg(feature = "checked_range_unsafe")]
62    #[inline]
63    pub fn get_mut<'a>(&self, slice: &'a mut [u8]) -> &'a mut [u8] {
64        unsafe {
65            #[cfg(debug_assertions)]
66            debug_assert_eq!(slice.as_ptr().add(self.start), self.original_ptr);
67
68            slice.get_unchecked_mut(self.start..self.end)
69        }
70    }
71
72    #[cfg(not(feature = "checked_range_unsafe"))]
73    #[inline]
74    pub fn get_mut<'a>(&self, slice: &'a mut [u8]) -> &'a mut [u8] {
75        &mut slice[self.start..self.end]
76    }
77
78    #[inline]
79    pub fn len(&self) -> usize {
80        self.end - self.start
81    }
82
83    #[inline]
84    pub fn is_empty(&self) -> bool {
85        self.start == self.end
86    }
87}
88
89impl fmt::Debug for CheckedRange {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        write!(f, "{}..{}", self.start, self.end)
92    }
93}
94
95#[cfg(test)]
96mod tests {
97
98    use super::*;
99
100    #[test]
101    #[cfg_attr(kani, kani::proof)]
102    fn checked_range_len() {
103        bolero::check!()
104            .with_type()
105            .for_each(|callee: &CheckedRange| Some(callee.len()));
106    }
107
108    #[test]
109    #[cfg_attr(kani, kani::proof)]
110    fn checked_range_is_empty() {
111        bolero::check!()
112            .with_type()
113            .for_each(|callee: &CheckedRange| Some(callee.is_empty()));
114    }
115}