ring/arithmetic/inout.rs
1// Copyright 2025 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(crate) use crate::error::LenMismatchError;
16use core::num::NonZeroUsize;
17
18pub(crate) trait AliasingSlices2<T> {
19 /// The pointers passed to `f` will be valid and non-null, and will not
20 /// be dangling, so they can be passed to C functions.
21 ///
22 /// The first pointer, `r`, may be pointing to uninitialized memory for
23 /// `expected_len` elements of type `T`, properly aligned and writable.
24 /// `f` must not read from `r` before writing to it.
25 ///
26 /// The second & third pointers, `a` and `b`, point to `expected_len`
27 /// values of type `T`, properly aligned.
28 ///
29 /// `r`, `a`, and/or `b` may alias each other only in the following ways:
30 /// `ptr::eq(r, a)`, `ptr::eq(r, b)`, and/or `ptr::eq(a, b)`; i.e. they
31 /// will not be "overlapping."
32 ///
33 /// Implementations of this trait shouldn't override this default
34 /// implementation.
35 #[inline(always)]
36 fn with_non_dangling_non_null_pointers_ra<R>(
37 self,
38 expected_len: NonZeroUsize,
39 f: impl FnOnce(*mut T, *const T) -> R,
40 ) -> Result<R, LenMismatchError>
41 where
42 Self: Sized,
43 {
44 self.with_potentially_dangling_non_null_pointers_ra(expected_len.get(), f)
45 }
46
47 /// If `expected_len == 0` then the pointers passed to `f` may be
48 /// dangling pointers, which should not be passed to C functions. In all
49 /// other respects, this works like
50 /// `Self::with_non_dangling_non_null_pointers_rab`.
51 ///
52 /// Implementations of this trait should implement this method and not
53 /// `with_non_dangling_non_null_pointers_rab`. Users of this trait should
54 /// use `with_non_dangling_non_null_pointers_rab` and not this.
55 fn with_potentially_dangling_non_null_pointers_ra<R>(
56 self,
57 expected_len: usize,
58 f: impl FnOnce(*mut T, *const T) -> R,
59 ) -> Result<R, LenMismatchError>;
60}
61
62impl<T> AliasingSlices2<T> for &mut [T] {
63 fn with_potentially_dangling_non_null_pointers_ra<R>(
64 self,
65 expected_len: usize,
66 f: impl FnOnce(*mut T, *const T) -> R,
67 ) -> Result<R, LenMismatchError> {
68 let r = self;
69 if r.len() != expected_len {
70 return Err(LenMismatchError::new(r.len()));
71 }
72 Ok(f(r.as_mut_ptr(), r.as_ptr()))
73 }
74}
75
76impl<T> AliasingSlices2<T> for (&mut [T], &[T]) {
77 fn with_potentially_dangling_non_null_pointers_ra<R>(
78 self,
79 expected_len: usize,
80 f: impl FnOnce(*mut T, *const T) -> R,
81 ) -> Result<R, LenMismatchError> {
82 let (r, a) = self;
83 if r.len() != expected_len {
84 return Err(LenMismatchError::new(r.len()));
85 }
86 if a.len() != expected_len {
87 return Err(LenMismatchError::new(a.len()));
88 }
89 Ok(f(r.as_mut_ptr(), a.as_ptr()))
90 }
91}
92
93pub(crate) trait AliasingSlices3<T> {
94 /// The pointers passed to `f` will all be non-null and properly aligned,
95 /// and will not be dangling.
96 ///
97 /// The first pointer, `r` points to potentially-uninitialized writable
98 /// space for `expected_len` elements of type `T`. Accordingly, `f` must
99 /// not read from `r` before writing to it.
100 ///
101 /// The second & third pointers, `a` and `b`, point to `expected_len`
102 /// initialized values of type `T`.
103 ///
104 /// `r`, `a`, and/or `b` may alias each other, but only in the following
105 /// ways: `ptr::eq(r, a)`, `ptr::eq(r, b)`, and/or `ptr::eq(a, b)`; they
106 /// will not be "overlapping."
107 ///
108 /// Implementations of this trait shouldn't override this default
109 /// implementation.
110 #[inline(always)]
111 fn with_non_dangling_non_null_pointers_rab<R>(
112 self,
113 expected_len: NonZeroUsize,
114 f: impl FnOnce(*mut T, *const T, *const T) -> R,
115 ) -> Result<R, LenMismatchError>
116 where
117 Self: Sized,
118 {
119 self.with_potentially_dangling_non_null_pointers_rab(expected_len.get(), f)
120 }
121
122 /// If `expected_len == 0` then the pointers passed to `f` may be
123 /// dangling pointers, which should not be passed to C functions. In all
124 /// other respects, this works like
125 /// `Self::with_non_dangling_non_null_pointers_rab`.
126 ///
127 /// Implementations of this trait should implement this method and not
128 /// `with_non_dangling_non_null_pointers_rab`. Users of this trait should
129 /// use `with_non_dangling_non_null_pointers_rab` and not this.
130 fn with_potentially_dangling_non_null_pointers_rab<R>(
131 self,
132 expected_len: usize,
133 f: impl FnOnce(*mut T, *const T, *const T) -> R,
134 ) -> Result<R, LenMismatchError>;
135}
136
137impl<T> AliasingSlices3<T> for &mut [T] {
138 fn with_potentially_dangling_non_null_pointers_rab<R>(
139 self,
140 expected_len: usize,
141 f: impl FnOnce(*mut T, *const T, *const T) -> R,
142 ) -> Result<R, LenMismatchError> {
143 <Self as AliasingSlices2<T>>::with_potentially_dangling_non_null_pointers_ra(
144 self,
145 expected_len,
146 |r, a| f(r, r, a),
147 )
148 }
149}
150
151impl<T> AliasingSlices3<T> for (&mut [T], &[T], &[T]) {
152 fn with_potentially_dangling_non_null_pointers_rab<R>(
153 self,
154 expected_len: usize,
155 f: impl FnOnce(*mut T, *const T, *const T) -> R,
156 ) -> Result<R, LenMismatchError> {
157 let (r, a, b) = self;
158 ((r, a), b).with_potentially_dangling_non_null_pointers_rab(expected_len, f)
159 }
160}
161
162impl<RA, T> AliasingSlices3<T> for (RA, &[T])
163where
164 RA: AliasingSlices2<T>,
165{
166 fn with_potentially_dangling_non_null_pointers_rab<R>(
167 self,
168 expected_len: usize,
169 f: impl FnOnce(*mut T, *const T, *const T) -> R,
170 ) -> Result<R, LenMismatchError> {
171 let (ra, b) = self;
172 if b.len() != expected_len {
173 return Err(LenMismatchError::new(b.len()));
174 }
175 ra.with_potentially_dangling_non_null_pointers_ra(expected_len, |r, a| f(r, a, b.as_ptr()))
176 }
177}