untrusted/
input.rs

1// Copyright 2015-2021 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use crate::{no_panic, Reader};
16
17/// A wrapper around `&'a [u8]` that helps in writing panic-free code.
18///
19/// No methods of `Input` will ever panic.
20///
21/// Intentionally avoids implementing `PartialEq` and `Eq` to avoid implicit
22/// non-constant-time comparisons.
23#[derive(Clone, Copy)]
24pub struct Input<'a> {
25    value: no_panic::Slice<'a>,
26}
27
28/// The value is intentionally omitted from the output to avoid leaking
29/// secrets.
30impl core::fmt::Debug for Input<'_> {
31    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32        f.debug_struct("Input").finish()
33    }
34}
35
36impl<'a> Input<'a> {
37    /// Construct a new `Input` for the given input `bytes`.
38    pub const fn from(bytes: &'a [u8]) -> Self {
39        // This limit is important for avoiding integer overflow. In particular,
40        // `Reader` assumes that an `i + 1 > i` if `input.value.get(i)` does
41        // not return `None`. According to the Rust language reference, the
42        // maximum object size is `core::isize::MAX`, and in practice it is
43        // impossible to create an object of size `core::usize::MAX` or larger.
44        Self {
45            value: no_panic::Slice::new(bytes),
46        }
47    }
48
49    /// Returns `true` if the input is empty and false otherwise.
50    #[inline]
51    pub fn is_empty(&self) -> bool {
52        self.value.is_empty()
53    }
54
55    /// Returns the length of the `Input`.
56    #[inline]
57    pub fn len(&self) -> usize {
58        self.value.len()
59    }
60
61    /// Calls `read` with the given input as a `Reader`, ensuring that `read`
62    /// consumed the entire input. If `read` does not consume the entire input,
63    /// `incomplete_read` is returned.
64    pub fn read_all<F, R, E>(&self, incomplete_read: E, read: F) -> Result<R, E>
65    where
66        F: FnOnce(&mut Reader<'a>) -> Result<R, E>,
67    {
68        let mut input = Reader::new(*self);
69        let result = read(&mut input)?;
70        if input.at_end() {
71            Ok(result)
72        } else {
73            Err(incomplete_read)
74        }
75    }
76
77    /// Access the input as a slice so it can be processed by functions that
78    /// are not written using the Input/Reader framework.
79    #[inline]
80    pub fn as_slice_less_safe(&self) -> &'a [u8] {
81        self.value.as_slice_less_safe()
82    }
83
84    pub(super) fn into_value(self) -> no_panic::Slice<'a> {
85        self.value
86    }
87}
88
89impl<'a> From<&'a [u8]> for Input<'a> {
90    #[inline]
91    fn from(value: &'a [u8]) -> Self {
92        no_panic::Slice::new(value).into()
93    }
94}
95
96impl<'a> From<no_panic::Slice<'a>> for Input<'a> {
97    #[inline]
98    fn from(value: no_panic::Slice<'a>) -> Self {
99        Self { value }
100    }
101}