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 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 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 | |
15 | pub(crate) use crate::error::LenMismatchError; |
16 | use core::num::NonZeroUsize; |
17 | |
18 | pub(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.into(), 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 | |
62 | impl<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: &mut [T] = 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 | |
76 | impl<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: &mut [T], a: &[T]) = 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 | |
93 | pub(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.into(), 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 | |
137 | impl<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: *mut T, a: *const T| f(r, r, a), |
147 | ) |
148 | } |
149 | } |
150 | |
151 | impl<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: &mut [T], a: &[T], b: &[T]) = self; |
158 | ((r, a), b).with_potentially_dangling_non_null_pointers_rab(expected_len, f) |
159 | } |
160 | } |
161 | |
162 | impl<RA, T> AliasingSlices3<T> for (RA, &[T]) |
163 | where |
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: RA, b: &[T]) = 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: *mut T, a: *const T| f(r, a, b.as_ptr())) |
176 | } |
177 | } |
178 | |