deferred_reference/slice_like_impl.rs
1//! This module contains method implementations for slice-like deferred references on [Deferred].
2
3use crate::{Deferred, PointerLength, Reference, SliceLike, SlicePointerIndex};
4
5/// # Methods only available for deferred references to slices and arrays
6/// [Deferred] overrides some of the standard methods for arrays and slices, in order to allow
7/// for deferred access to disjoint indices. The idea is that if you only need a reference
8/// to a specific element or subslice, then it is not necessary to create a reference to the
9/// entire array or slice. The overriden methods are listed below. In addition to the overriden
10/// methods listed below, [Deferred] also overrides the [Index](core::ops::Index) and
11/// [IndexMut](core::ops::IndexMut) traits on slices and arrays. This allows for direct access
12/// to disjoint subslices, without triggering undefined behavior, using the syntactic sugar of
13/// Rust:
14/// ```
15/// use deferred_reference::Deferred;
16/// let mut buffer = [0u8; 300];
17/// let mut a = Deferred::from(&mut buffer); // a mutable deferred reference
18/// let b = unsafe { a.clone_unchecked().into_ref() }; // immutable deferred reference
19/// let mut c = unsafe { a.clone_unchecked() }; // another mutable deferred reference
20/// let mut_ref1 = &mut a[0..100];
21/// assert_eq!(&[0u8; 100], &b[100..200]);
22/// c[200..].copy_from_slice(&[1u8; 100]);
23/// assert_eq!(&mut [1u8; 100], &mut c[200..]);
24/// assert_eq!(&mut [0u8; 100], mut_ref1);
25/// ```
26/// The above example also works on stable Rust, because `buffer` is an array. However, for slices
27/// this will not work on stable Rust, at least not until the
28/// [`slice_ptr_len`](https://github.com/rust-lang/rust/issues/71146) feature is stabilized.
29/// On nightly Rust, this is already possible with slices, too. In order to work with slices
30/// on stable Rust (or on nightly Rust without the unstable features disabled), you will need to
31/// insert an explicit call to [Deref::deref](core::ops::Deref::deref) or
32/// [DerefMut::deref_mut](core::ops::DerefMut::deref_mut) in order to reach the slice,
33/// which will create a reference to the entire slice (without this extra step, you will get a panic).
34/// This is made explicit like this to avoid ambiguity when a method resolves to a subslice or
35/// the entire slice. Here is an example of how to use [Deferred] on stable Rust with slices,
36/// under the condition that indexing operations are disjoint in lifetime (instead of disjoint
37/// w.r.t. the indices):
38/// ```
39/// use deferred_reference::Deferred;
40/// use core::ops::{Deref, DerefMut};
41/// let mut buffer = [0u8; 300];
42/// let mut a: Deferred<&mut [u8]> = Deferred::from(&mut buffer).into(); // a slice
43/// let b = unsafe { a.clone_unchecked().into_ref() }; // immutable deferred reference
44/// let mut c = unsafe { a.clone_unchecked() }; // another mutable deferred reference;
45/// let mut_ref1 = &mut a.deref_mut()[0..100]; // accesses `a` for lifetime 'a
46/// assert_eq!(&mut [0u8; 100], &mut mut_ref1[0..100]); // lifetime 'a ends after this statement
47/// assert_eq!(&[0u8; 100], &b.deref()[100..200]); // accesses `b` for short-lived lifetime 'b
48/// c.deref_mut()[200..].copy_from_slice(&[1u8; 100]); // accesses `c` for short-lived lifetime 'c
49/// assert_eq!(&mut [1u8; 100], &mut c.deref_mut()[200..]); // accesses `c` for lifetime 'd
50/// ```
51impl<T> Deferred<T>
52where
53 T: Reference,
54 T::Target: SliceLike,
55{
56 /// Obtains the length of the array or slice that this `Deferred` points to, without creating
57 /// an intermediate reference to the array or slice.
58 ///
59 /// # Example
60 /// ```
61 /// use core::cell::UnsafeCell;
62 /// use deferred_reference::{Defer, Deferred};
63 /// let buffer = UnsafeCell::new([0u8; 1024]);
64 /// let deferred: Deferred<_> = buffer.defer();
65 /// assert_eq!(1024, deferred.len());
66 /// ```
67 ///
68 /// # Panics
69 /// As of yet, the length of slices (which are a dynamically sized type, unlike fixed size arrays)
70 /// can only be accessed when the unstable `Cargo.toml` feature `slice_ptr_len` or `unstable` is enabled.
71 /// If you call this method on a deferred slice without one of these features enabled, then this method will panic.
72 /// This method will become panic-less for slices when the `slice_ptr_len` feature lands in Rust stable,
73 /// see <https://github.com/rust-lang/rust/issues/71146>. It is still possible to access the length
74 /// of a fixed sized array `[T; N]` without dereferencing the array in stable Rust (meaning, even
75 /// without the use of unstable features and without risk of panics).
76 pub fn len(&self) -> usize {
77 PointerLength::len(self.as_ptr())
78 }
79
80 /// Returns a reference to an element or subslice depending on the type of
81 /// index, without creating a reference to the other elements in the slice.
82 ///
83 /// - If given a position, returns a reference to the element at that
84 /// position or `None` if out of bounds.
85 /// - If given a range, returns the subslice corresponding to that range,
86 /// or `None` if out of bounds.
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// use deferred_reference::Deferred;
92 /// let v = Deferred::from(&[10, 40, 30]);
93 /// assert_eq!(Some(&40), v.get(1));
94 /// assert_eq!(Some(&[10, 40][..]), v.get(0..2));
95 /// assert_eq!(None, v.get(3));
96 /// assert_eq!(None, v.get(0..4));
97 /// ```
98 #[inline]
99 pub fn get<I>(&self, index: I) -> Option<&I::Output>
100 where
101 I: SlicePointerIndex<T::Target>,
102 {
103 index.get(self.as_ptr()).map(|ptr| {
104 // SAFETY: `ptr` is checked to be in bounds, so this is safe
105 unsafe { &*ptr }
106 })
107 }
108
109 /// Returns a reference to an element or subslice, without doing bounds checking and without
110 /// creating a reference to the other elements in the slice.
111 ///
112 /// For a safe alternative see [`get`].
113 ///
114 /// # Safety
115 ///
116 /// Calling this method with an out-of-bounds index is *[undefined behavior]*
117 /// even if the resulting reference is not used.
118 ///
119 /// [`get`]: #method.get
120 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
121 ///
122 /// # Examples
123 ///
124 /// ```
125 /// use deferred_reference::Deferred;
126 /// let x = Deferred::from(&[1, 2, 4]);
127 ///
128 /// unsafe {
129 /// assert_eq!(x.get_unchecked(1), &2);
130 /// }
131 /// ```
132 #[inline]
133 pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
134 where
135 I: SlicePointerIndex<T::Target>,
136 {
137 // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
138 // SAFETY: the slice is dereferencable because `self.as_ptr()` is a safe pointer.
139 // SAFETY: the returned pointer is safe because impls of `SlicePointerIndex` have to guarantee that it is.
140 &*index.get_unchecked(self.as_ptr())
141 }
142
143 /// Divides one deferred slice into two deferred slices at an index, without doing bounds checking
144 /// and without creating any intermediate references.
145 ///
146 /// The first will contain all indices from `[0, mid)` (excluding
147 /// the index `mid` itself) and the second will contain all
148 /// indices from `[mid, len)` (excluding the index `len` itself).
149 ///
150 /// For a safe alternative see [`split_at`].
151 ///
152 /// # Safety
153 ///
154 /// Calling this method with an out-of-bounds index is *[undefined behavior]*
155 /// even if the resulting reference is not used. The caller has to ensure that
156 /// `0 <= mid <= self.len()`.
157 ///
158 /// [`split_at`]: #method.split_at
159 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
160 ///
161 /// # Examples
162 ///
163 /// ```
164 /// use deferred_reference::Deferred;
165 /// let v = [1, 2, 3, 4, 5, 6];
166 /// let deferred = Deferred::new(&v);
167 ///
168 /// unsafe {
169 /// let (left, right) = deferred.split_at_unchecked(0);
170 /// assert_eq!(*left, []);
171 /// assert_eq!(*right, [1, 2, 3, 4, 5, 6]);
172 /// }
173 ///
174 /// unsafe {
175 /// let (left, right) = deferred.split_at_unchecked(2);
176 /// assert_eq!(*left, [1, 2]);
177 /// assert_eq!(*right, [3, 4, 5, 6]);
178 /// }
179 ///
180 /// unsafe {
181 /// let (left, right) = deferred.split_at_unchecked(6);
182 /// assert_eq!(*left, [1, 2, 3, 4, 5, 6]);
183 /// assert_eq!(*right, []);
184 /// }
185 /// ```
186 #[inline]
187 pub unsafe fn split_at_unchecked(&self, mid: usize) -> (Deferred<&[<T::Target as SliceLike>::Element]>, Deferred<&[<T::Target as SliceLike>::Element]>){
188 // SAFETY: Caller has to check that `0 <= mid <= self.len()`.
189 // SAFETY: the other invariants are then upheld by SlicePointerIndex and Deferred.
190 (
191 Deferred::from_raw((..mid).get_unchecked(self.as_ptr())),
192 Deferred::from_raw((mid..).get_unchecked(self.as_ptr()))
193 )
194 }
195
196 /// Divides one deferred slice into two deferred slices at an index,
197 /// without creating any intermediate references.
198 ///
199 /// The first will contain all indices from `[0, mid)` (excluding
200 /// the index `mid` itself) and the second will contain all
201 /// indices from `[mid, len)` (excluding the index `len` itself).
202 ///
203 /// # Panics
204 ///
205 /// Panics if `mid > len`.
206 ///
207 /// # Examples
208 ///
209 /// ```
210 /// use deferred_reference::Deferred;
211 /// let v = [1, 2, 3, 4, 5, 6];
212 /// let deferred = Deferred::new(&v);
213 /// {
214 /// let (left, right) = deferred.split_at(0);
215 /// assert_eq!(*left, []);
216 /// assert_eq!(*right, [1, 2, 3, 4, 5, 6]);
217 /// }
218 ///
219 /// {
220 /// let (left, right) = deferred.split_at(2);
221 /// assert_eq!(*left, [1, 2]);
222 /// assert_eq!(*right, [3, 4, 5, 6]);
223 /// }
224 ///
225 /// {
226 /// let (left, right) = deferred.split_at(6);
227 /// assert_eq!(*left, [1, 2, 3, 4, 5, 6]);
228 /// assert_eq!(*right, []);
229 /// }
230 ///
231 /// {
232 /// // this method overrides the `<[T]>::split_at` method from the core library
233 /// // if you rather have actual slices than deferred slices, insert a `deref` like so:
234 /// use core::ops::Deref;
235 /// let (left, right) /* : (&[_], &[_]) */ = deferred.deref().split_at(2);
236 /// assert_eq!(left, [1, 2]);
237 /// assert_eq!(right, [3, 4, 5, 6]);
238 /// }
239 /// ```
240 #[inline]
241 pub fn split_at(&self, mid: usize) -> (Deferred<&[<T::Target as SliceLike>::Element]>, Deferred<&[<T::Target as SliceLike>::Element]>) {
242 assert!(mid <= self.len());
243 // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
244 // SAFETY: fulfills the requirements of `split_at_unchecked`.
245 unsafe { self.split_at_unchecked(mid) }
246 }
247}
248
249/// # Methods only available for deferred _mutable_ references to slices and arrays
250impl<T> Deferred<&mut T>
251where
252 T: SliceLike + ?Sized,
253{
254 /// Returns a mutable reference to an element or subslice depending on the
255 /// type of index (see [`get`]) or `None` if the index is out of bounds.
256 /// This method will not create a reference to the other elements in the slice.
257 ///
258 /// [`get`]: #method.get
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use deferred_reference::Deferred;
264 /// use core::ops::Deref;
265 /// let mut x = [0, 1, 2];
266 /// let mut x = Deferred::from(&mut x);
267 ///
268 /// if let Some(elem) = x.get_mut(1) {
269 /// *elem = 42;
270 /// }
271 /// assert_eq!(x.deref(), &[0, 42, 2]);
272 /// ```
273 #[inline]
274 pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
275 where
276 I: SlicePointerIndex<T>,
277 {
278 index.get_mut(self.as_mut_ptr()).map(|ptr| {
279 // SAFETY: `ptr` is checked to be in bounds, so this is safe
280 unsafe { &mut *ptr }
281 })
282 }
283
284 /// Returns a mutable reference to an element or subslice, without doing bounds checking and without
285 /// creating a reference to the other elements in the slice.
286 ///
287 /// For a safe alternative see [`get_mut`].
288 ///
289 /// # Safety
290 ///
291 /// Calling this method with an out-of-bounds index is *[undefined behavior]*
292 /// even if the resulting reference is not used.
293 ///
294 /// [`get_mut`]: #method.get_mut
295 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
296 ///
297 /// # Examples
298 ///
299 /// ```
300 /// use deferred_reference::Deferred;
301 /// use core::ops::Deref;
302 /// let mut x = [1, 2, 4];
303 /// let mut x = Deferred::from(&mut x);
304 ///
305 /// unsafe {
306 /// let elem = x.get_unchecked_mut(1);
307 /// *elem = 13;
308 /// }
309 /// assert_eq!(x.deref(), &[1, 13, 4]);
310 /// ```
311 #[inline]
312 pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
313 where
314 I: SlicePointerIndex<T>,
315 {
316 // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
317 // SAFETY: the slice is dereferencable because `self` is a safe pointer.
318 // SAFETY: The returned pointer is safe because impls of `SlicePointerIndex` have to guarantee that it is.
319 &mut *index.get_unchecked_mut(self.as_mut_ptr())
320 }
321
322 /// Divides one deferred mutable slice into two deferred mutable slice at an index, without doing bounds checking
323 /// and without creating any intermediate references.
324 ///
325 /// The first will contain all indices from `[0, mid)` (excluding
326 /// the index `mid` itself) and the second will contain all
327 /// indices from `[mid, len)` (excluding the index `len` itself).
328 ///
329 /// For a safe alternative see [`split_at_mut`].
330 ///
331 /// # Safety
332 ///
333 /// Calling this method with an out-of-bounds index is *[undefined behavior]*
334 /// even if the resulting reference is not used. The caller has to ensure that
335 /// `0 <= mid <= self.len()`.
336 ///
337 /// [`split_at_mut`]: #method.split_at_mut
338 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
339 ///
340 /// # Examples
341 ///
342 /// ```
343 /// use deferred_reference::Deferred;
344 /// let mut v = [1, 0, 3, 0, 5, 6];
345 /// let mut deferred = Deferred::new_mut(&mut v);
346 /// // scoped to restrict the lifetime of the borrows
347 /// unsafe {
348 /// let (mut left, mut right) = deferred.split_at_mut_unchecked(2);
349 /// assert_eq!(*left, [1, 0]);
350 /// assert_eq!(*right, [3, 0, 5, 6]);
351 /// left[1] = 2;
352 /// right[1] = 4;
353 /// }
354 /// assert_eq!(*deferred, [1, 2, 3, 4, 5, 6]);
355 /// ```
356 #[inline]
357 pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (Deferred<&mut [T::Element]>, Deferred<&mut [T::Element]>) {
358 // SAFETY: Caller has to check that `0 <= mid <= self.len()`.
359 // SAFETY: the other invariants are then upheld by SlicePointerIndex and Deferred.
360 (
361 Deferred::from_raw_mut((..mid).get_unchecked_mut(self.as_mut_ptr())),
362 Deferred::from_raw_mut((mid..).get_unchecked_mut(self.as_mut_ptr()))
363 )
364 }
365
366 /// Divides one mutable slice into two at an index.
367 ///
368 /// The first will contain all indices from `[0, mid)` (excluding
369 /// the index `mid` itself) and the second will contain all
370 /// indices from `[mid, len)` (excluding the index `len` itself).
371 ///
372 /// # Panics
373 ///
374 /// Panics if `mid > len`.
375 ///
376 /// # Examples
377 ///
378 /// ```
379 /// use deferred_reference::Deferred;
380 /// let mut v = [1, 0, 3, 0, 5, 6];
381 /// let mut deferred = Deferred::new_mut(&mut v);
382 /// let (mut left, mut right) = deferred.split_at_mut(2);
383 /// assert_eq!(*left, [1, 0]);
384 /// assert_eq!(*right, [3, 0, 5, 6]);
385 /// left[1] = 2;
386 /// right[1] = 4;
387 /// assert_eq!(*deferred, [1, 2, 3, 4, 5, 6]);
388 /// // this method overrides the `<[T]>::split_at_mut` method from the core library
389 /// // if you rather have actual slices than deferred slices, insert a `deref_mut` like so:
390 /// use core::ops::DerefMut;
391 /// let (left, right) /* : (&mut [_], &mut [_]) */ = deferred.deref_mut().split_at(2);
392 /// assert_eq!(*left, [1, 2]);
393 /// assert_eq!(*right, [3, 4, 5, 6]);
394 /// ```
395 #[inline]
396 pub fn split_at_mut(&mut self, mid: usize) -> (Deferred<&mut [T::Element]>, Deferred<&mut [T::Element]>) {
397 assert!(mid <= self.len());
398 // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
399 // SAFETY: fulfills the requirements of `split_at_mut_unchecked`.
400 unsafe { self.split_at_mut_unchecked(mid) }
401 }
402}
403
404#[cfg(test)]
405mod tests {
406 use alloc::vec::Vec;
407 use alloc::boxed::Box;
408 use core::cell::UnsafeCell;
409 use core::ops::{Deref, DerefMut};
410 use crate::{DeferMut, Deferred};
411
412 #[test]
413 fn doctest1() {
414 let mut buffer = [0u8; 300];
415 let mut a = Deferred::from(&mut buffer); // a mutable deferred reference
416 let b = unsafe { a.clone_unchecked().into_ref() }; // immutable deferred reference
417 let mut c = unsafe { a.clone_unchecked() }; // another mutable deferred reference
418 let mut_ref1 = &mut a[0..100];
419 assert_eq!(&[0u8; 100], &b[100..200]);
420 c[200..].copy_from_slice(&[1u8; 100]);
421 assert_eq!(&mut [1u8; 100], &mut c[200..]);
422 assert_eq!(&mut [0u8; 100], mut_ref1);
423 }
424
425 #[test]
426 fn doctest2() {
427 let mut buffer = [0u8; 300];
428 let mut a: Deferred<&mut [u8]> = Deferred::from(&mut buffer).into(); // a mutable deferred reference
429 let b = unsafe { a.clone_unchecked().into_ref() }; // immutable deferred reference
430 let mut c = unsafe { a.clone_unchecked() }; // another mutable deferred reference;
431 let mut_ref1 = &mut a.deref_mut()[0..100]; // accesses `a` for lifetime 'a
432 assert_eq!(&mut [0u8; 100], &mut mut_ref1[0..100]); // lifetime 'a ends after this statement
433 assert_eq!(&[0u8; 100], &b.deref()[100..200]); // accesses `b` for short-lived lifetime 'b
434 c.deref_mut()[200..].copy_from_slice(&[1u8; 100]); // accesses `c` for short-lived lifetime 'c
435 assert_eq!(&mut [1u8; 100], &mut c.deref_mut()[200..]); // accesses `c` for short-lived lifetime 'd
436 }
437
438
439 #[test]
440 fn len_array() {
441 let mut buffer = [0u8; 1024];
442 let ptr = core::ptr::addr_of!(buffer);
443 let deferred = unsafe { Deferred::from_raw(ptr) };
444 assert_eq!(1024, deferred.len());
445
446 let ptr = core::ptr::addr_of_mut!(buffer);
447 let deferred = unsafe { Deferred::from_raw_mut(ptr) };
448 assert_eq!(1024, deferred.len());
449 }
450
451 #[test]
452 fn len_slice() {
453 let mut buffer = Vec::with_capacity(1024);
454 buffer.resize(1024, 0u8);
455 let ptr = &buffer[..] as *const [u8];
456 let deferred = unsafe { Deferred::from_raw(ptr) };
457 Deferred::len(&deferred);
458 assert_eq!(1024, deferred.len());
459
460 let ptr = core::ptr::slice_from_raw_parts_mut(buffer.as_mut_ptr(), buffer.len());
461 let deferred = unsafe { Deferred::from_raw_mut(ptr) };
462 assert_eq!(1024, deferred.len());
463 }
464
465 /// Tests that length of arrays can be obtained without dereferencing them.
466 #[test]
467 fn test_array_len_ub() {
468 let buffer = UnsafeCell::new([0u8; 1024]);
469 // SAFETY: there are no references active whatsoever, so this is safe.
470 let mut deferred = unsafe { buffer.defer_mut() };
471 // SAFETY: we launder the lifetime of the mutable reference, but we promise not to alias it
472 let mut_borrow = unsafe { &mut *(deferred.deref_mut() as *mut [u8; 1024]) };
473 assert_eq!(1024, deferred.len()); // should not create any references to pointee
474 // ensure that mutable borrow persists until end of this function:
475 assert_eq!(0, mut_borrow[0]);
476 }
477
478 /// Tests that length of slices can be obtained without dereferencing them.
479 #[test]
480 fn test_slice_len_ub() {
481 let mut vector = Vec::with_capacity(1024);
482 vector.resize(1024, 0u8);
483 let boxed_slice = vector.into_boxed_slice();
484 // SAFETY: UnsafeCell is #[repr(transparent)] so this is safe.
485 let buffer: Box<UnsafeCell<[u8]>> = unsafe { core::mem::transmute(boxed_slice) };
486 // SAFETY: we won't dereference this deferred reference.
487 let mut deferred = unsafe { buffer.defer_mut() };
488 // SAFETY: we launder the lifetime of a mutable reference, but we promise not to alias it
489 let mut_borrow = unsafe { &mut *(deferred.deref_mut() as *mut [u8]) };
490 assert_eq!(1024, deferred.len()); // should not create any references to pointee
491 // ensure that mutable borrow persists until end of this function:
492 assert_eq!(0, mut_borrow[0]);
493 }
494
495 #[test]
496 fn core_split_at_mut() {
497 let mut buffer = [1, 2, 3];
498 let mut_ref = &mut buffer;
499 let (left, right) = mut_ref.split_at_mut(1);
500 assert_eq!(&mut [1], left);
501 assert_eq!(&mut [2, 3], right);
502 assert_eq!([1, 2, 3], *mut_ref);
503 }
504}