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}