ring/aead/overlapping/
base.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2024 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

pub use self::index_error::IndexError;
use super::Array;
use crate::error::LenMismatchError;
use core::{mem, ops::RangeFrom};

pub struct Overlapping<'o, T> {
    // Invariant: self.src.start <= in_out.len().
    in_out: &'o mut [T],
    src: RangeFrom<usize>,
}

impl<'o, T> From<&'o mut [T]> for Overlapping<'o, T> {
    fn from(in_out: &'o mut [T]) -> Self {
        Self { in_out, src: 0.. }
    }
}

impl<'o, T> Overlapping<'o, T> {
    pub fn new(in_out: &'o mut [T], src: RangeFrom<usize>) -> Result<Self, IndexError> {
        match in_out.get(src.clone()) {
            Some(_) => Ok(Self { in_out, src }),
            None => Err(IndexError::new(src.start)),
        }
    }

    #[cfg(any(
        all(target_arch = "arm", target_endian = "little"),
        target_arch = "x86"
    ))]
    pub fn copy_within(self) -> &'o mut [T]
    where
        T: Copy,
    {
        if self.src.start == 0 {
            self.in_out
        } else {
            let len = self.len();
            self.in_out.copy_within(self.src, 0);
            &mut self.in_out[..len]
        }
    }

    #[cfg(any(
        all(target_arch = "arm", target_endian = "little"),
        target_arch = "x86"
    ))]
    pub fn into_slice_src_mut(self) -> (&'o mut [T], RangeFrom<usize>) {
        (self.in_out, self.src)
    }

    pub fn into_unwritten_output(self) -> &'o mut [T] {
        let len = self.len();
        self.in_out.get_mut(..len).unwrap_or_else(|| {
            // The invariant ensures this succeeds.
            unreachable!()
        })
    }
}

impl<T> Overlapping<'_, T> {
    pub fn len(&self) -> usize {
        self.input().len()
    }

    pub fn input(&self) -> &[T] {
        self.in_out.get(self.src.clone()).unwrap_or_else(|| {
            // Ensured by invariant.
            unreachable!()
        })
    }

    pub fn with_input_output_len<R>(self, f: impl FnOnce(*const T, *mut T, usize) -> R) -> R {
        let len = self.len();
        let output = self.in_out.as_mut_ptr();
        // TODO: MSRV(1.65): use `output.cast_const()`
        let output_const: *const T = output;
        // SAFETY: The constructor ensures that `src` is a valid range.
        // Equivalent to `self.in_out[src.clone()].as_ptr()` but without
        // worries about compatibility with the stacked borrows model.
        // TODO(MSRV-1.80, probably): Avoid special casing 0; see
        // https://github.com/rust-lang/rust/pull/117329
        // https://github.com/rust-lang/rustc_codegen_gcc/issues/516
        let input = if self.src.start == 0 {
            output_const
        } else {
            unsafe { output_const.add(self.src.start) }
        };
        f(input, output, len)
    }

    // Perhaps unlike `slice::split_first_chunk_mut`, this is biased,
    // performance-wise, against the case where `N > self.len()`, so callers
    // should be structured to avoid that.
    //
    // If the result is `Err` then nothing was written to `self`; if anything
    // was written then the result will not be `Err`.
    #[cfg_attr(not(test), allow(dead_code))]
    pub fn split_first_chunk<const N: usize>(
        mut self,
        f: impl for<'a> FnOnce(Array<'a, T, N>),
    ) -> Result<Self, IndexError> {
        let src = self.src.clone();
        let end = self
            .src
            .start
            .checked_add(N)
            .ok_or_else(|| IndexError::new(N))?;
        let first = self
            .in_out
            .get_mut(..end)
            .ok_or_else(|| IndexError::new(N))?;
        let first = Overlapping::new(first, src).unwrap_or_else(|IndexError { .. }| {
            // Since `end == src.start + N`.
            unreachable!()
        });
        let first = Array::new(first).unwrap_or_else(|LenMismatchError { .. }| {
            // Since `end == src.start + N`.
            unreachable!()
        });
        // Once we call `f`, we must return `Ok` because `f` may have written
        // over (part of) the input.
        Ok({
            f(first);
            let tail = mem::take(&mut self.in_out).get_mut(N..).unwrap_or_else(|| {
                // There are at least `N` elements since `end == src.start + N`.
                unreachable!()
            });
            Self::new(tail, self.src).unwrap_or_else(|IndexError { .. }| {
                // Follows from `end == src.start + N`.
                unreachable!()
            })
        })
    }
}

cold_exhaustive_error! {
    struct index_error::IndexError { index: usize }
}