ring/aead/overlapping/
base.rs

1// Copyright 2024 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 AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15pub use self::index_error::IndexError;
16use super::Array;
17use crate::error::LenMismatchError;
18use core::{mem, ops::RangeFrom};
19
20pub struct Overlapping<'o, T> {
21    // Invariant: self.src.start <= in_out.len().
22    in_out: &'o mut [T],
23    src: RangeFrom<usize>,
24}
25
26impl<'o, T> From<&'o mut [T]> for Overlapping<'o, T> {
27    fn from(in_out: &'o mut [T]) -> Self {
28        Self { in_out, src: 0.. }
29    }
30}
31
32impl<'o, T> Overlapping<'o, T> {
33    pub fn new(in_out: &'o mut [T], src: RangeFrom<usize>) -> Result<Self, IndexError> {
34        match in_out.get(src.clone()) {
35            Some(_) => Ok(Self { in_out, src }),
36            None => Err(IndexError::new(src.start)),
37        }
38    }
39
40    #[cfg(any(
41        all(target_arch = "arm", target_endian = "little"),
42        target_arch = "x86"
43    ))]
44    pub fn copy_within(self) -> &'o mut [T]
45    where
46        T: Copy,
47    {
48        if self.src.start == 0 {
49            self.in_out
50        } else {
51            let len = self.len();
52            self.in_out.copy_within(self.src, 0);
53            &mut self.in_out[..len]
54        }
55    }
56
57    #[cfg(any(
58        all(target_arch = "arm", target_endian = "little"),
59        target_arch = "x86"
60    ))]
61    pub fn into_slice_src_mut(self) -> (&'o mut [T], RangeFrom<usize>) {
62        (self.in_out, self.src)
63    }
64
65    pub fn into_unwritten_output(self) -> &'o mut [T] {
66        let len = self.len();
67        self.in_out.get_mut(..len).unwrap_or_else(|| {
68            // The invariant ensures this succeeds.
69            unreachable!()
70        })
71    }
72}
73
74impl<T> Overlapping<'_, T> {
75    pub fn len(&self) -> usize {
76        self.input().len()
77    }
78
79    pub fn input(&self) -> &[T] {
80        self.in_out.get(self.src.clone()).unwrap_or_else(|| {
81            // Ensured by invariant.
82            unreachable!()
83        })
84    }
85
86    pub fn with_input_output_len<R>(self, f: impl FnOnce(*const T, *mut T, usize) -> R) -> R {
87        let len = self.len();
88        let output = self.in_out.as_mut_ptr();
89        // TODO: MSRV(1.65): use `output.cast_const()`
90        let output_const: *const T = output;
91        // SAFETY: The constructor ensures that `src` is a valid range.
92        // Equivalent to `self.in_out[src.clone()].as_ptr()` but without
93        // worries about compatibility with the stacked borrows model.
94        // TODO(MSRV-1.80, probably): Avoid special casing 0; see
95        // https://github.com/rust-lang/rust/pull/117329
96        // https://github.com/rust-lang/rustc_codegen_gcc/issues/516
97        let input = if self.src.start == 0 {
98            output_const
99        } else {
100            unsafe { output_const.add(self.src.start) }
101        };
102        f(input, output, len)
103    }
104
105    // Perhaps unlike `slice::split_first_chunk_mut`, this is biased,
106    // performance-wise, against the case where `N > self.len()`, so callers
107    // should be structured to avoid that.
108    //
109    // If the result is `Err` then nothing was written to `self`; if anything
110    // was written then the result will not be `Err`.
111    #[cfg_attr(not(test), allow(dead_code))]
112    pub fn split_first_chunk<const N: usize>(
113        mut self,
114        f: impl for<'a> FnOnce(Array<'a, T, N>),
115    ) -> Result<Self, IndexError> {
116        let src = self.src.clone();
117        let end = self
118            .src
119            .start
120            .checked_add(N)
121            .ok_or_else(|| IndexError::new(N))?;
122        let first = self
123            .in_out
124            .get_mut(..end)
125            .ok_or_else(|| IndexError::new(N))?;
126        let first = Overlapping::new(first, src).unwrap_or_else(|IndexError { .. }| {
127            // Since `end == src.start + N`.
128            unreachable!()
129        });
130        let first = Array::new(first).unwrap_or_else(|LenMismatchError { .. }| {
131            // Since `end == src.start + N`.
132            unreachable!()
133        });
134        // Once we call `f`, we must return `Ok` because `f` may have written
135        // over (part of) the input.
136        Ok({
137            f(first);
138            let tail = mem::take(&mut self.in_out).get_mut(N..).unwrap_or_else(|| {
139                // There are at least `N` elements since `end == src.start + N`.
140                unreachable!()
141            });
142            Self::new(tail, self.src).unwrap_or_else(|IndexError { .. }| {
143                // Follows from `end == src.start + N`.
144                unreachable!()
145            })
146        })
147    }
148}
149
150cold_exhaustive_error! {
151    struct index_error::IndexError { index: usize }
152}