Skip to main content

inout/
inout.rs

1use crate::InOutBuf;
2use core::{marker::PhantomData, ops::Mul, ptr};
3use hybrid_array::{Array, ArraySize, typenum::Prod};
4
5/// Custom pointer type which contains one immutable (input) and one mutable
6/// (output) pointer, which are either equal or non-overlapping.
7pub struct InOut<'inp, 'out, T> {
8    pub(crate) in_ptr: *const T,
9    pub(crate) out_ptr: *mut T,
10    pub(crate) _pd: PhantomData<(&'inp T, &'out mut T)>,
11}
12
13impl<'inp, 'out, T> InOut<'inp, 'out, T> {
14    /// Reborrow `self`.
15    #[inline(always)]
16    pub fn reborrow(&mut self) -> InOut<'_, '_, T> {
17        Self {
18            in_ptr: self.in_ptr,
19            out_ptr: self.out_ptr,
20            _pd: PhantomData,
21        }
22    }
23
24    /// Get immutable reference to the input value.
25    #[inline(always)]
26    #[must_use]
27    pub fn get_in(&self) -> &T {
28        unsafe { &*self.in_ptr }
29    }
30
31    /// Get mutable reference to the output value.
32    #[inline(always)]
33    pub fn get_out(&mut self) -> &mut T {
34        unsafe { &mut *self.out_ptr }
35    }
36
37    /// Consume `self` and get mutable reference to the output value with lifetime `'out`
38    /// and output value equal to the input value.
39    ///
40    /// In the case if the input and output references are the same, simply returns
41    /// the output reference. Otherwise, copies data from the former to the latter
42    /// before returning the output reference.
43    #[must_use]
44    pub fn into_out_with_copied_in(self) -> &'out mut T
45    where
46        T: Copy,
47    {
48        if !ptr::eq(self.in_ptr, self.out_ptr) {
49            unsafe {
50                ptr::copy(self.in_ptr, self.out_ptr, 1);
51            }
52        }
53        unsafe { &mut *self.out_ptr }
54    }
55
56    /// Consume `self` and get mutable reference to the output value with lifetime `'out`.
57    #[inline(always)]
58    #[must_use]
59    pub fn into_out(self) -> &'out mut T {
60        unsafe { &mut *self.out_ptr }
61    }
62
63    /// Convert `self` to a pair of raw input and output pointers.
64    #[inline(always)]
65    #[must_use]
66    pub fn into_raw(self) -> (*const T, *mut T) {
67        (self.in_ptr, self.out_ptr)
68    }
69
70    /// Create `InOut` from raw input and output pointers.
71    ///
72    /// # Safety
73    /// Behavior is undefined if any of the following conditions are violated:
74    /// - `in_ptr` must point to a properly initialized value of type `T` and
75    ///   must be valid for reads.
76    /// - `out_ptr` must point to a properly initialized value of type `T` and
77    ///   must be valid for both reads and writes.
78    /// - `in_ptr` and `out_ptr` must be either equal or non-overlapping.
79    /// - If `in_ptr` and `out_ptr` are equal, then the memory referenced by
80    ///   them must not be accessed through any other pointer (not derived from
81    ///   the return value) for the duration of lifetime 'a. Both read and write
82    ///   accesses are forbidden.
83    /// - If `in_ptr` and `out_ptr` are not equal, then the memory referenced by
84    ///   `out_ptr` must not be accessed through any other pointer (not derived from
85    ///   the return value) for the duration of lifetime `'a`. Both read and write
86    ///   accesses are forbidden. The memory referenced by `in_ptr` must not be
87    ///   mutated for the duration of lifetime `'a`, except inside an `UnsafeCell`.
88    #[inline(always)]
89    pub unsafe fn from_raw(in_ptr: *const T, out_ptr: *mut T) -> InOut<'inp, 'out, T> {
90        Self {
91            in_ptr,
92            out_ptr,
93            _pd: PhantomData,
94        }
95    }
96}
97
98impl<T: Clone> InOut<'_, '_, T> {
99    /// Clone input value and return it.
100    #[inline(always)]
101    #[must_use]
102    pub fn clone_in(&self) -> T {
103        unsafe { (*self.in_ptr).clone() }
104    }
105}
106
107impl<'a, T> From<&'a mut T> for InOut<'a, 'a, T> {
108    #[inline(always)]
109    fn from(val: &'a mut T) -> Self {
110        let p = ptr::from_mut(val);
111        Self {
112            in_ptr: p,
113            out_ptr: p,
114            _pd: PhantomData,
115        }
116    }
117}
118
119impl<'inp, 'out, T> From<(&'inp T, &'out mut T)> for InOut<'inp, 'out, T> {
120    #[inline(always)]
121    fn from((in_val, out_val): (&'inp T, &'out mut T)) -> Self {
122        Self {
123            in_ptr: ptr::from_ref::<T>(in_val),
124            out_ptr: ptr::from_mut::<T>(out_val),
125            _pd: Default::default(),
126        }
127    }
128}
129
130impl<'inp, 'out, T, N: ArraySize> InOut<'inp, 'out, Array<T, N>> {
131    /// Returns `InOut` for the given position.
132    ///
133    /// # Panics
134    /// If `pos` greater or equal to array length.
135    #[inline(always)]
136    pub fn get(&mut self, pos: usize) -> InOut<'_, '_, T> {
137        assert!(pos < N::USIZE);
138        unsafe {
139            InOut {
140                in_ptr: self.in_ptr.cast::<T>().add(pos),
141                out_ptr: self.out_ptr.cast::<T>().add(pos),
142                _pd: PhantomData,
143            }
144        }
145    }
146
147    /// Convert `InOut` array to `InOutBuf`.
148    #[inline(always)]
149    #[must_use]
150    pub fn into_buf(self) -> InOutBuf<'inp, 'out, T> {
151        InOutBuf {
152            in_ptr: self.in_ptr.cast::<T>(),
153            out_ptr: self.out_ptr.cast::<T>(),
154            len: N::USIZE,
155            _pd: PhantomData,
156        }
157    }
158}
159
160impl<'inp, 'out, T, N, M> From<InOut<'inp, 'out, Array<T, Prod<N, M>>>>
161    for Array<InOut<'inp, 'out, Array<T, N>>, M>
162where
163    N: ArraySize,
164    M: ArraySize,
165    N: Mul<M>,
166    Prod<N, M>: ArraySize,
167{
168    fn from(buf: InOut<'inp, 'out, Array<T, Prod<N, M>>>) -> Self {
169        let in_ptr: *const Array<T, N> = buf.in_ptr.cast();
170        let out_ptr: *mut Array<T, N> = buf.out_ptr.cast();
171
172        Array::from_fn(|i| unsafe {
173            InOut {
174                in_ptr: in_ptr.add(i),
175                out_ptr: out_ptr.add(i),
176                _pd: PhantomData,
177            }
178        })
179    }
180}
181
182impl<N: ArraySize> InOut<'_, '_, Array<u8, N>> {
183    /// XOR `data` with values behind the input slice and write
184    /// result to the output slice.
185    ///
186    /// # Panics
187    /// If `data` length is not equal to the buffer length.
188    #[inline(always)]
189    pub fn xor_in2out(&mut self, data: &Array<u8, N>) {
190        unsafe {
191            let input = ptr::read(self.in_ptr);
192            let mut temp = Array::<u8, N>::default();
193            for i in 0..N::USIZE {
194                temp[i] = input[i] ^ data[i];
195            }
196            ptr::write(self.out_ptr, temp);
197        }
198    }
199}
200
201impl<N, M> InOut<'_, '_, Array<Array<u8, N>, M>>
202where
203    N: ArraySize,
204    M: ArraySize,
205{
206    /// XOR `data` with values behind the input slice and write
207    /// result to the output slice.
208    ///
209    /// # Panics
210    /// If `data` length is not equal to the buffer length.
211    #[inline(always)]
212    pub fn xor_in2out(&mut self, data: &Array<Array<u8, N>, M>) {
213        unsafe {
214            let input = ptr::read(self.in_ptr);
215            let mut temp = Array::<Array<u8, N>, M>::default();
216            for i in 0..M::USIZE {
217                for j in 0..N::USIZE {
218                    temp[i][j] = input[i][j] ^ data[i][j];
219                }
220            }
221            ptr::write(self.out_ptr, temp);
222        }
223    }
224}