scratchpad/
traits.rs

1// Copyright 2018-2021 Theodore Cipicchio
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Support traits.
10
11use core::ptr;
12use core::slice;
13use core::str;
14
15use super::{ArrayIter, CacheAligned};
16use core::mem::size_of;
17#[cfg(any(stable_maybe_uninit, feature = "unstable"))]
18use core::mem::MaybeUninit;
19
20#[cfg(feature = "std")]
21use std::ffi::CStr;
22
23#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
24use super::{Box, Vec};
25
26/// Trait for types that can be safely used as the backing data type for
27/// storage of arbitrary data.
28///
29/// `ByteData` is implemented by default for all basic integer types as well
30/// as the [`CacheAligned`] struct provided by this crate.
31///
32/// # Safety
33///
34/// This trait is used to help constrain implementations of the [`Buffer`]
35/// trait to known types that are considered "safe" to use as the backing
36/// storage type of a buffer. To properly implement this trait, the type
37/// should have the following characteristics:
38///
39/// - Allow arbitrary bytes within instances of the type to be left
40///   uninitialized without any possible side effects (outside of attempts to
41///   explicitly read those bytes). In particular, types should not have
42///   [`Drop`] trait implementations that rely on the data to be in any
43///   particular state.
44/// - Allow arbitrary bytes within instances of the type to be written to with
45///   arbitrary values without affecting other bytes.
46/// - Allow previously written bytes to be read back regardless of whether
47///   other bytes have been written to yet (only bytes that have been
48///   explicitly written to are expected to be read back).
49///
50/// [`Buffer`]: trait.Buffer.html
51/// [`CacheAligned`]: struct.CacheAligned.html
52/// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html
53pub unsafe trait ByteData: Sized {}
54
55unsafe impl ByteData for u8 {}
56unsafe impl ByteData for u16 {}
57unsafe impl ByteData for u32 {}
58unsafe impl ByteData for u64 {}
59#[cfg(any(stable128, feature = "unstable"))]
60unsafe impl ByteData for u128 {}
61unsafe impl ByteData for usize {}
62unsafe impl ByteData for i8 {}
63unsafe impl ByteData for i16 {}
64unsafe impl ByteData for i32 {}
65unsafe impl ByteData for i64 {}
66#[cfg(any(stable128, feature = "unstable"))]
67unsafe impl ByteData for i128 {}
68unsafe impl ByteData for isize {}
69unsafe impl ByteData for CacheAligned {}
70
71#[cfg(any(stable_maybe_uninit, feature = "unstable"))]
72unsafe impl<T: ByteData> ByteData for MaybeUninit<T> {}
73
74/// Trait for static arrays.
75///
76/// # Safety
77///
78/// This trait is declared as unsafe to signify that it should only be
79/// implemented for static arrays (`[T; x]` for some size x). Implementing it
80/// for other types can result in undefined behavior and instability.
81pub unsafe trait Array {
82    /// Array item type.
83    type Item: Sized;
84
85    /// Returns a slice of the entire array.
86    fn as_slice(&self) -> &[Self::Item];
87
88    /// Returns a mutable slice of the entire array.
89    fn as_mut_slice(&mut self) -> &mut [Self::Item];
90}
91
92/// Trait for [`Scratchpad`] buffer types.
93///
94/// `Buffer` objects contain the memory from which [`Scratchpad`] allocations
95/// are made. [`Scratchpad`] handles all bookkeeping, so a buffer only needs
96/// to provide methods for raw access of the buffer memory.
97///
98/// [`Scratchpad`]: struct.Scratchpad.html
99pub trait Buffer {
100    /// Returns a byte slice of the buffer contents.
101    fn as_bytes(&self) -> &[u8];
102    /// Returns a mutable byte slice of the buffer contents.
103    fn as_bytes_mut(&mut self) -> &mut [u8];
104}
105
106impl<T> Buffer for T
107where
108    T: Array,
109    <T as Array>::Item: ByteData,
110{
111    #[inline]
112    fn as_bytes(&self) -> &[u8] {
113        let data = self.as_slice();
114        unsafe {
115            slice::from_raw_parts(
116                data.as_ptr() as *const u8,
117                data.len() * size_of::<<T as Array>::Item>(),
118            )
119        }
120    }
121
122    #[inline]
123    fn as_bytes_mut(&mut self) -> &mut [u8] {
124        let data = self.as_mut_slice();
125        unsafe {
126            slice::from_raw_parts_mut(
127                data.as_mut_ptr() as *mut u8,
128                data.len() * size_of::<<T as Array>::Item>(),
129            )
130        }
131    }
132}
133
134impl<'a, T> Buffer for &'a mut [T]
135where
136    T: ByteData,
137{
138    #[inline]
139    fn as_bytes(&self) -> &[u8] {
140        unsafe {
141            slice::from_raw_parts(
142                self.as_ptr() as *const u8,
143                self.len() * size_of::<T>(),
144            )
145        }
146    }
147
148    #[inline]
149    fn as_bytes_mut(&mut self) -> &mut [u8] {
150        unsafe {
151            slice::from_raw_parts_mut(
152                self.as_mut_ptr() as *mut u8,
153                self.len() * size_of::<T>(),
154            )
155        }
156    }
157}
158
159#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
160impl<T> Buffer for Box<[T]>
161where
162    T: ByteData,
163{
164    #[inline]
165    fn as_bytes(&self) -> &[u8] {
166        let data = self.as_ref();
167        unsafe {
168            slice::from_raw_parts(
169                data.as_ptr() as *const u8,
170                data.len() * size_of::<T>(),
171            )
172        }
173    }
174
175    #[inline]
176    fn as_bytes_mut(&mut self) -> &mut [u8] {
177        let data = self.as_mut();
178        unsafe {
179            slice::from_raw_parts_mut(
180                data.as_mut_ptr() as *mut u8,
181                data.len() * size_of::<T>(),
182            )
183        }
184    }
185}
186
187/// [`Buffer`] sub-trait for static arrays.
188///
189/// This trait is used specifically to restrict the implementation of
190/// [`Scratchpad::static_new()`] to static array buffers.
191///
192/// # Safety
193///
194/// [`Scratchpad::static_new()`] leaves instances of this type **entirely**
195/// uninitialized, so implementing it is fundamentally unsafe. It should only
196/// be implemented by static arrays of [`ByteData`] types.
197///
198/// [`Buffer`]: trait.Buffer.html
199/// [`ByteData`]: trait.ByteData.html
200/// [`Scratchpad::static_new()`]: struct.Scratchpad.html#method.static_new
201pub unsafe trait StaticBuffer: Buffer + Array {}
202
203unsafe impl<T> StaticBuffer for T
204where
205    T: Array,
206    <T as Array>::Item: ByteData,
207{
208}
209
210/// Trait for [`Scratchpad`] allocation tracking containers.
211///
212/// Each [`Marker`] is tracked within a [`Scratchpad`] using only a single
213/// `usize` value per allocation. Actual storage of such values can be
214/// implemented in any manner (memory does not need to be contiguous, for
215/// instance).
216///
217/// [`Scratchpad`] and [`Marker`] will never call [`get()`] for a given index
218/// if [`set()`] has not been previously called for the same index, so values
219/// can be left uninitialized prior to [`set()`] calls.
220///
221/// [`get()`]: #method.get.html
222/// [`Marker`]: trait.Marker.html
223/// [`Scratchpad`]: struct.Scratchpad.html
224/// [`set()`]: #method.set.html
225pub trait Tracking: Sized {
226    /// Returns the total number of allocations that can be stored in this
227    /// container.
228    fn capacity(&self) -> usize;
229    /// Stores a value at the specified index.
230    fn set(&mut self, index: usize, value: usize);
231    /// Retrieves the value from the specified index.
232    fn get(&self, index: usize) -> usize;
233}
234
235impl<T> Tracking for T
236where
237    T: Buffer,
238{
239    #[inline]
240    fn capacity(&self) -> usize {
241        self.as_bytes().len() / size_of::<usize>()
242    }
243
244    #[cfg_attr(
245        feature = "cargo-clippy",
246        allow(clippy::cast_ptr_alignment, clippy::size_of_in_element_count)
247    )]
248    #[inline]
249    fn set(&mut self, index: usize, value: usize) {
250        let bytes = self.as_bytes_mut();
251        unsafe {
252            let contents = slice::from_raw_parts_mut(
253                bytes.as_mut_ptr() as *mut usize,
254                bytes.len() / size_of::<usize>(),
255            );
256            ptr::write_unaligned(&mut contents[index], value);
257        }
258    }
259
260    #[cfg_attr(
261        feature = "cargo-clippy",
262        allow(clippy::cast_ptr_alignment, clippy::size_of_in_element_count)
263    )]
264    #[inline]
265    fn get(&self, index: usize) -> usize {
266        let bytes = self.as_bytes();
267        unsafe {
268            let contents = slice::from_raw_parts(
269                bytes.as_ptr() as *const usize,
270                bytes.len() / size_of::<usize>(),
271            );
272            ptr::read_unaligned(&contents[index])
273        }
274    }
275}
276
277/// Trait for dynamically sized types that wrap some slice type.
278///
279/// Some DSTs, such as [`str`], are mostly a wrapper for a basic slice type,
280/// often providing some abstraction to ensure the data isn't used in an
281/// unsafe manner. Implementing this trait for such DSTs exposes conversions
282/// to and from the slice type, allowing us to use these types with allocation
283/// operations.
284///
285/// [`str`]: https://doc.rust-lang.org/std/primitive.str.html
286pub trait SliceLike {
287    /// Slice element type.
288    type Element: Sized;
289
290    /// Returns a slice of `Self::Element` elements containing this slice's
291    /// data.
292    ///
293    /// # Examples
294    ///
295    /// ```
296    /// use scratchpad::SliceLike;
297    ///
298    /// let message = "foo";
299    /// let bytes = message.as_element_slice();
300    /// assert_eq!(bytes, &[b'f', b'o', b'o']);
301    /// ```
302    fn as_element_slice(&self) -> &[Self::Element];
303
304    /// Returns a mutable slice of `Self::Element` elements containing this
305    /// slice's data.
306    ///
307    /// # Safety
308    ///
309    /// Slices of this type may perform validity checks against the internal
310    /// data (e.g. `str` slices must contain valid UTF-8 data). This function
311    /// allows for modification of the slice contents outside such checks.
312    /// Improper use of this function can result in undefined behavior.
313    ///
314    /// # Examples
315    ///
316    /// ```
317    /// use scratchpad::SliceLike;
318    ///
319    /// let mut message = String::from("foo");
320    ///
321    /// unsafe {
322    ///     let bytes = message.as_mut_str().as_element_slice_mut();
323    ///     bytes[0] = b'b';
324    ///     bytes[1] = b'a';
325    ///     bytes[2] = b'r';
326    /// }
327    ///
328    /// assert_eq!(message, "bar");
329    /// ```
330    unsafe fn as_element_slice_mut(&mut self) -> &mut [Self::Element];
331
332    /// Reinterprets a slice of `Self::Inner` elements as a slice of this
333    /// type.
334    ///
335    /// # Safety
336    ///
337    /// Slices of this type may perform validity checks against the internal
338    /// data (e.g. `str` slices must contain valid UTF-8 data). This function
339    /// bypasses any such checks, potentially returning data that is invalid.
340    /// Improper use of this function can result in undefined behavior.
341    ///
342    /// # Examples
343    ///
344    /// ```
345    /// use scratchpad::SliceLike;
346    ///
347    /// let bytes = [b'f', b'o', b'o'];
348    /// let message = unsafe {
349    ///     <str as SliceLike>::from_element_slice(&bytes[..])
350    /// };
351    /// assert_eq!(message, "foo");
352    /// ```
353    unsafe fn from_element_slice(slice: &[Self::Element]) -> &Self;
354
355    /// Reinterprets a mutable slice of `Self::Inner` elements as a mutable
356    /// slice of this type.
357    ///
358    /// # Safety
359    ///
360    /// Slices of this type may perform validity checks against the internal
361    /// data (e.g. `str` slices must contain valid UTF-8 data). This function
362    /// bypasses any such checks, potentially returning data that is invalid.
363    /// Improper use of this function can result in undefined behavior.
364    ///
365    /// # Examples
366    ///
367    /// ```
368    /// use scratchpad::SliceLike;
369    ///
370    /// let mut bytes = [b'f', b'o', b'o'];
371    ///
372    /// unsafe {
373    ///     let message = <str as SliceLike>::from_element_slice_mut(
374    ///         &mut bytes[..],
375    ///     );
376    ///     message.as_bytes_mut()[0] = b'b';
377    ///     message.as_bytes_mut()[1] = b'a';
378    ///     message.as_bytes_mut()[2] = b'r';
379    /// }
380    ///
381    /// assert_eq!(bytes, [b'b', b'a', b'r']);
382    /// ```
383    unsafe fn from_element_slice_mut(
384        slice: &mut [Self::Element],
385    ) -> &mut Self;
386}
387
388impl<T> SliceLike for [T] {
389    type Element = T;
390
391    #[inline]
392    fn as_element_slice(&self) -> &[Self::Element] {
393        self
394    }
395
396    #[inline]
397    unsafe fn as_element_slice_mut(&mut self) -> &mut [Self::Element] {
398        self
399    }
400
401    #[inline]
402    unsafe fn from_element_slice(slice: &[Self::Element]) -> &Self {
403        slice
404    }
405
406    #[inline]
407    unsafe fn from_element_slice_mut(
408        slice: &mut [Self::Element],
409    ) -> &mut Self {
410        slice
411    }
412}
413
414impl SliceLike for str {
415    type Element = u8;
416
417    #[inline]
418    fn as_element_slice(&self) -> &[Self::Element] {
419        self.as_bytes()
420    }
421
422    #[inline]
423    unsafe fn as_element_slice_mut(&mut self) -> &mut [Self::Element] {
424        self.as_bytes_mut()
425    }
426
427    #[inline]
428    unsafe fn from_element_slice(slice: &[Self::Element]) -> &Self {
429        str::from_utf8_unchecked(slice)
430    }
431
432    #[inline]
433    unsafe fn from_element_slice_mut(
434        slice: &mut [Self::Element],
435    ) -> &mut Self {
436        str::from_utf8_unchecked_mut(slice)
437    }
438}
439
440#[cfg(feature = "std")]
441impl SliceLike for CStr {
442    /// Slice element type.
443    ///
444    /// `u8` is used as the element type instead of [`c_char`], as the
445    /// [`CStr`] methods that handle conversions to and from slices work with
446    /// `u8` slices (`c_char` is only used when working with raw pointers).
447    ///
448    /// [`c_char`]: https://doc.rust-lang.org/std/os/raw/type.c_char.html
449    /// [`CStr`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html
450    type Element = u8;
451
452    /// Returns a slice of `Self::Element` elements containing this slice's
453    /// data.
454    ///
455    /// This uses [`CStr::to_bytes_with_nul()`] to return the entire [`CStr`]
456    /// contents, including the nul terminator.
457    ///
458    /// # Examples
459    ///
460    /// ```
461    /// use scratchpad::SliceLike;
462    /// use std::ffi::CString;
463    ///
464    /// let message = CString::new("foo").unwrap();
465    /// let message_c_str = message.as_c_str();
466    /// let bytes = message_c_str.as_element_slice();
467    /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
468    /// ```
469    ///
470    /// [`CStr::to_bytes_with_nul()`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html#method.to_bytes_with_nul
471    /// [`CStr`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html
472    #[inline]
473    fn as_element_slice(&self) -> &[Self::Element] {
474        self.to_bytes_with_nul()
475    }
476
477    /// Returns a mutable slice of `Self::Element` elements containing this
478    /// slice's data.
479    ///
480    /// This is roughly equivalent to [`CStr::to_bytes_with_nul()`], returning
481    /// a mutable slice instead of an immutable slice.
482    ///
483    /// # Safety
484    ///
485    /// This function potentially allows for modification of the [`CStr`]
486    /// contents outside of any validity checks, specifically checks for a nul
487    /// terminator and no internal nul bytes. Improper use of this function
488    /// can result in undefined behavior.
489    ///
490    /// # Examples
491    ///
492    /// ```
493    /// use scratchpad::SliceLike;
494    /// use std::ffi::{CStr, CString};
495    ///
496    /// let mut message = CString::new("foo").unwrap().into_boxed_c_str();
497    /// let message_c_str = &mut *message;
498    ///
499    /// unsafe {
500    ///     let bytes = message_c_str.as_element_slice_mut();
501    ///     bytes[0] = b'b';
502    ///     bytes[1] = b'a';
503    ///     bytes[2] = b'r';
504    /// }
505    ///
506    /// assert_eq!(
507    ///     message_c_str,
508    ///     CStr::from_bytes_with_nul(b"bar\0").unwrap(),
509    /// );
510    /// ```
511    ///
512    /// [`CStr::to_bytes_with_nul()`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html#method.to_bytes_with_nul
513    /// [`CStr`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html
514    #[inline]
515    unsafe fn as_element_slice_mut(&mut self) -> &mut [Self::Element] {
516        // TODO: Converting from a constant reference to a mutable reference
517        //       is technically undefined behavior, but aliasing of the
518        //       constant reference is prevented by the fact that we take a
519        //       mutable reference to the `CStr` slice as an argument.
520        //       Regardless, a better alternative should be found if possible.
521        // LINT: Allowing mutable cast for the time being (see above TODO).
522        #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ref_to_mut))]
523        &mut *(self.to_bytes_with_nul() as *const [u8] as *mut [u8])
524    }
525
526    /// Reinterprets a slice of `Self::Inner` elements as a slice of this
527    /// type.
528    ///
529    /// This uses [`CStr::from_bytes_with_nul_unchecked()`] to create a
530    /// [`CStr`] from a nul-terminated byte slice.
531    ///
532    /// # Safety
533    ///
534    /// No safety checking is performed on the provided byte slice. It
535    /// **must** be nul-terminated and not contain any interior nul bytes.
536    ///
537    /// # Examples
538    ///
539    /// ```
540    /// use scratchpad::SliceLike;
541    /// use std::ffi::CStr;
542    ///
543    /// let bytes = [b'f', b'o', b'o', b'\0'];
544    /// let message = unsafe {
545    ///     <CStr as SliceLike>::from_element_slice(&bytes[..])
546    /// };
547    /// assert_eq!(message, CStr::from_bytes_with_nul(b"foo\0").unwrap());
548    /// ```
549    ///
550    /// [`CStr::from_bytes_with_nul_unchecked()`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html#method.from_bytes_with_nul_unchecked
551    /// [`CStr`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html
552    #[inline]
553    unsafe fn from_element_slice(slice: &[Self::Element]) -> &Self {
554        CStr::from_bytes_with_nul_unchecked(slice)
555    }
556
557    /// Reinterprets a mutable slice of `Self::Inner` elements as a mutable
558    /// slice of this type.
559    ///
560    /// This is roughly equivalent to
561    /// [`CStr::from_bytes_with_nul_unchecked()`], returning a mutable
562    /// [`CStr`] reference instead of an immutable reference.
563    ///
564    /// # Safety
565    ///
566    /// No safety checking is performed on the provided byte slice. It
567    /// **must** be nul-terminated and not contain any interior nul bytes.
568    ///
569    /// # Examples
570    ///
571    /// ```
572    /// use scratchpad::SliceLike;
573    /// use std::ffi::CStr;
574    ///
575    /// let mut bytes = [b'f', b'o', b'o', b'\0'];
576    /// let message = unsafe {
577    ///     <CStr as SliceLike>::from_element_slice_mut(&mut bytes[..])
578    /// };
579    /// assert_eq!(message, CStr::from_bytes_with_nul(b"foo\0").unwrap());
580    /// ```
581    ///
582    /// [`CStr::from_bytes_with_nul_unchecked()`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html#method.from_bytes_with_nul_unchecked
583    /// [`CStr`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html
584    #[inline]
585    unsafe fn from_element_slice_mut(
586        slice: &mut [Self::Element],
587    ) -> &mut Self {
588        // TODO: This makes the same assumption as `as_element_slice_mut()`
589        //       above with regards to casting from a constant reference to a
590        //       mutable reference. Seeing as it still falls under the blanket
591        //       of undefined behavior, an alternative should be used if
592        //       possible.
593        // LINT: Allowing mutable cast for the time being (see above TODO).
594        #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ref_to_mut))]
595        &mut *(CStr::from_bytes_with_nul_unchecked(slice) as *const CStr
596            as *mut CStr)
597    }
598}
599
600/// Extension of the [`SliceLike`] trait used to mark DSTs for which
601/// concatenation can safely be performed by concatenating the underlying
602/// slice type.
603///
604/// This is used as a constraint for functions such as
605/// [`Allocation::concat()`] and [`MarkerFront::append()`].
606///
607/// [`Allocation::concat()`]: struct.Allocation.html#method.concat
608/// [`MarkerFront::append()`]: struct.MarkerFront.html#method.append
609/// [`SliceLike`]: trait.SliceLike.html
610pub trait ConcatenateSlice: SliceLike {}
611
612impl<T> ConcatenateSlice for [T] {}
613impl ConcatenateSlice for str {}
614
615/// Trait for reinterpreting a pointer to a given type as a compatible
616/// [`SliceLike`] pointer that uses the exact same backing memory.
617///
618/// # Safety
619///
620/// This trait is marked as unsafe due to the potential for data loss if
621/// implemented incorrectly. It is used within this crate to determine which
622/// slice conversions are valid for a given [`Allocation`] without requiring
623/// the allocated data to be modified in any way. The source and destination
624/// types must use the same exact storage memory, and dropping the data stored
625/// in the destination type must also perform any cleanup required by the
626/// original source type.
627///
628/// [`Allocation`]: struct.Allocation.html
629/// [`SliceLike`]: trait.SliceLike.html
630pub unsafe trait IntoMutSliceLikePtr<T>
631where
632    T: SliceLike + ?Sized,
633{
634    /// Reinterprets a mutable pointer of this type as a [`SliceLike`]
635    /// pointer.
636    ///
637    /// # Examples
638    ///
639    /// ```
640    /// use scratchpad::IntoMutSliceLikePtr;
641    ///
642    /// let mut value = 3.14159;
643    /// let value_ptr: *mut f64 = &mut value;
644    ///
645    /// let slice_ptr = IntoMutSliceLikePtr::into_mut_slice_like_ptr(
646    ///     value_ptr,
647    /// );
648    /// assert_eq!(unsafe { &*slice_ptr }, [3.14159]);
649    /// ```
650    ///
651    /// [`SliceLike`]: trait.SliceLike.html
652    // LINT: `wrong_self_convention` lint wasn't present when this method was
653    //       added. Altering it to satisfy the lint warning would be a
654    //       SemVer-breaking change, so it will have to be deferred to a later
655    //       major version.
656    #[cfg_attr(
657        feature = "cargo-clippy",
658        allow(clippy::wrong_self_convention)
659    )]
660    fn into_mut_slice_like_ptr(ptr: *mut Self) -> *mut T;
661}
662
663unsafe impl<T> IntoMutSliceLikePtr<[T]> for T {
664    // LINT: `ptr` doesn't get dereferenced by `slice::from_raw_parts_mut()`,
665    //       so the lint error can be ignored.
666    #[cfg_attr(
667        feature = "cargo-clippy",
668        allow(clippy::not_unsafe_ptr_arg_deref)
669    )]
670    #[inline]
671    fn into_mut_slice_like_ptr(ptr: *mut T) -> *mut [T] {
672        unsafe { slice::from_raw_parts_mut(ptr, 1) }
673    }
674}
675
676unsafe impl<T> IntoMutSliceLikePtr<T> for T
677where
678    T: SliceLike + ?Sized,
679{
680    #[inline]
681    fn into_mut_slice_like_ptr(ptr: *mut T) -> *mut T {
682        ptr
683    }
684}
685
686unsafe impl IntoMutSliceLikePtr<[u8]> for str {
687    // LINT: Despite the notation, `ptr` doesn't actually get dereferenced by
688    //       this function (only the pointer value itself is ever read), so
689    //       the lint error can be ignored.
690    #[cfg_attr(
691        feature = "cargo-clippy",
692        allow(clippy::not_unsafe_ptr_arg_deref)
693    )]
694    #[inline]
695    fn into_mut_slice_like_ptr(ptr: *mut str) -> *mut [u8] {
696        unsafe { (*ptr).as_bytes_mut() }
697    }
698}
699
700#[cfg(feature = "std")]
701unsafe impl IntoMutSliceLikePtr<[u8]> for CStr {
702    // TODO: While the current implementation of `CStr` doesn't require
703    //       dereferencing `ptr` in order to convert to a `*mut [u8]`, it may
704    //       in the future, so the `not_unsafe_ptr_arg_deref` lint warning is
705    //       valid in this context. Since `IntoMutSliceLikePtr` is a public
706    //       trait, adding `unsafe` to this function would be a breaking
707    //       change, so we can't do so until the 2.0 release.
708    #[cfg_attr(
709        feature = "cargo-clippy",
710        allow(clippy::not_unsafe_ptr_arg_deref)
711    )]
712    #[inline]
713    fn into_mut_slice_like_ptr(ptr: *mut CStr) -> *mut [u8] {
714        unsafe { (*ptr).as_element_slice_mut() }
715    }
716}
717
718/// Trait for sources of slice data provided to [`Marker`] trait methods.
719///
720/// `SliceSource` is implemented for static arrays and slice references. If
721/// either the `std` or `unstable` features are enabled, [boxed slice] and
722/// [`Vec`] instances can be used as slice sources as well.
723///
724/// `SliceSource` on its own is only usable for `Clone` and `Copy` data
725/// sources. For move operations, the [`SliceMoveSource`] subtrait provides
726/// additional functionality for moving slices out of supported types.
727///
728/// [`Marker`]: trait.Marker.html
729/// [`SliceMoveSource`]: trait.SliceMoveSource.html
730/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
731/// [boxed slice]: https://doc.rust-lang.org/std/boxed/struct.Box.html
732pub trait SliceSource<T>
733where
734    T: SliceLike + ?Sized,
735{
736    /// Returns a [`SliceLike`] reference to this object's data.
737    ///
738    /// # Examples
739    ///
740    /// ```
741    /// use scratchpad::SliceSource;
742    ///
743    /// // `value` is an `[f64; 1]`...
744    /// let value = [3.14159];
745    ///
746    /// // ...but `value_slice` is a `&[f64]`...
747    /// let value_slice = value.as_slice_like();
748    /// assert_eq!(value_slice.len(), 1);
749    /// assert_eq!(value_slice[0], 3.14159);
750    ///
751    /// // ...that references the same memory as `value`.
752    /// assert!(std::ptr::eq(&value[0], &value_slice[0]));
753    /// ```
754    ///
755    /// [`SliceLike`]: trait.SliceLike.html
756    fn as_slice_like(&self) -> &T;
757
758    /// Returns a [`SliceLike`] pointer to this object's data.
759    ///
760    /// # Examples
761    ///
762    /// ```
763    /// use scratchpad::SliceSource;
764    ///
765    /// // `value` is an `[f64; 1]`...
766    /// let value = [3.14159];
767    ///
768    /// unsafe {
769    ///     // ...but `value_slice_ptr` is a `*const [f64]`...
770    ///     let value_slice_ptr = value.as_slice_like_ptr();
771    ///     assert_eq!((*value_slice_ptr).len(), 1);
772    ///     assert_eq!((*value_slice_ptr)[0], 3.14159);
773    ///
774    ///     // ...that references the same memory as `value`.
775    ///     assert!(std::ptr::eq(&value[0], &(*value_slice_ptr)[0]));
776    /// }
777    /// ```
778    ///
779    /// [`SliceLike`]: trait.SliceLike.html
780    #[inline(always)]
781    fn as_slice_like_ptr(&self) -> *const T {
782        self.as_slice_like()
783    }
784}
785
786impl<T> SliceSource<[<T as Array>::Item]> for T
787where
788    T: Array,
789{
790    #[inline]
791    fn as_slice_like(&self) -> &[<T as Array>::Item] {
792        self.as_slice()
793    }
794}
795
796impl<'a, T> SliceSource<T> for &'a T
797where
798    T: SliceLike + ?Sized,
799{
800    #[inline]
801    fn as_slice_like(&self) -> &T {
802        *self
803    }
804}
805
806#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
807impl<T> SliceSource<T> for Box<T>
808where
809    T: SliceLike + ?Sized,
810{
811    #[inline]
812    fn as_slice_like(&self) -> &T {
813        &**self
814    }
815}
816
817#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
818impl<T> SliceSource<[T]> for Vec<T> {
819    #[inline]
820    fn as_slice_like(&self) -> &[T] {
821        self.as_slice()
822    }
823}
824
825#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
826impl<'a, T> SliceSource<T> for &'a Box<T>
827where
828    T: SliceLike + ?Sized,
829{
830    #[inline]
831    fn as_slice_like(&self) -> &T {
832        &***self
833    }
834}
835
836#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
837impl<'a, T> SliceSource<[T]> for &'a Vec<T> {
838    #[inline]
839    fn as_slice_like(&self) -> &[T] {
840        self.as_slice()
841    }
842}
843
844/// Subtrait of [`SliceSource`] for taking ownership of the contents of a
845/// slice.
846///
847/// [`SliceSource`]: trait.SliceSource.html
848pub trait SliceMoveSource<T>: SliceSource<T>
849where
850    T: SliceLike + ?Sized,
851{
852    /// Calls a closure for each item in this source, consuming the source.
853    ///
854    /// # Examples
855    ///
856    /// ```
857    /// use scratchpad::SliceMoveSource;
858    ///
859    /// fn move_to_vec<T: SliceMoveSource<[i32]>>(source: T) -> Vec<i32> {
860    ///     let mut out = Vec::new();
861    ///     source.move_elements(|x| out.push(x));
862    ///     out
863    /// }
864    ///
865    /// let values = [5, 6, 7, 8];
866    /// let out = move_to_vec([5, 6, 7, 8]);
867    /// assert_eq!(*out, [5, 6, 7, 8]);
868    /// ```
869    fn move_elements<F>(self, f: F)
870    where
871        Self: Sized,
872        F: FnMut(<T as SliceLike>::Element);
873}
874
875impl<T> SliceMoveSource<[<T as Array>::Item]> for T
876where
877    T: Array,
878{
879    fn move_elements<F>(self, mut f: F)
880    where
881        F: FnMut(<T as Array>::Item),
882    {
883        for item in ArrayIter::new(self) {
884            f(item);
885        }
886    }
887}
888
889impl<'a, T> SliceMoveSource<T> for &'a T
890where
891    T: SliceLike + ?Sized,
892    <T as SliceLike>::Element: Copy,
893{
894    fn move_elements<F>(self, mut f: F)
895    where
896        F: FnMut(<T as SliceLike>::Element),
897    {
898        for item in self.as_element_slice() {
899            f(*item);
900        }
901    }
902}
903
904#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
905impl<T> SliceMoveSource<T> for Box<T>
906where
907    T: SliceLike + ?Sized,
908{
909    fn move_elements<F>(self, mut f: F)
910    where
911        F: FnMut(<T as SliceLike>::Element),
912    {
913        let boxed_slice = unsafe {
914            Box::from_raw((*Box::into_raw(self)).as_element_slice_mut()
915                as *mut [T::Element])
916        };
917
918        for item in boxed_slice.into_vec() {
919            f(item);
920        }
921    }
922}
923
924#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
925impl<T> SliceMoveSource<[T]> for Vec<T> {
926    fn move_elements<F>(self, mut f: F)
927    where
928        F: FnMut(T),
929    {
930        for item in self {
931            f(item);
932        }
933    }
934}
935
936#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
937impl<'a, T> SliceMoveSource<T> for &'a Box<T>
938where
939    T: SliceLike + ?Sized,
940    <T as SliceLike>::Element: Copy,
941{
942    fn move_elements<F>(self, mut f: F)
943    where
944        F: FnMut(<T as SliceLike>::Element),
945    {
946        for item in self.as_element_slice() {
947            f(*item);
948        }
949    }
950}
951
952#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
953impl<'a, T> SliceMoveSource<[T]> for &'a Vec<T>
954where
955    T: Copy,
956{
957    fn move_elements<F>(self, mut f: F)
958    where
959        F: FnMut(T),
960    {
961        for item in self {
962            f(*item);
963        }
964    }
965}
966
967/// Trait for generic access to collections of [`SliceSource`] objects.
968///
969/// Collections can be either arrays, tuples, or slices of [`SliceSource`]
970/// objects. Tuples can contain contain objects of different [`SliceSource`]
971/// implementation types. If either the `std` or `unstable` features are
972/// enabled, [`boxed slice`] and [`Vec`] instances can be used as slice
973/// source collections as well.
974///
975/// `SliceSourceCollection` on its own is only usable for `Clone` and `Copy`
976/// data sources. For move operations, the [`SliceMoveSourceCollection`]
977/// subtrait provides additional functionality for moving slices out of
978/// supported types.
979///
980/// [`boxed slice`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
981/// [`Marker`]: trait.Marker.html
982/// [`SliceMoveSourceCollection`]: trait.SliceMoveSourceCollection.html
983/// [`SliceSource`]: trait.SliceSource.html
984/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
985pub trait SliceSourceCollection<T>
986where
987    T: SliceLike + ?Sized,
988{
989    /// Calls a closure for each [`SliceSource`] in this collection.
990    ///
991    /// # Examples
992    ///
993    /// ```
994    /// use scratchpad::{SliceLike, SliceSourceCollection};
995    ///
996    /// let collection = ([1, 2, 3], [4], [5, 6]);
997    ///
998    /// let mut out = Vec::new();
999    /// collection.for_each(|source| {
1000    ///     for x in source.as_slice_like().as_element_slice() {
1001    ///         out.push(*x * 2);
1002    ///     }
1003    /// });
1004    /// assert_eq!(*out, [2, 4, 6, 8, 10, 12]);
1005    /// ```
1006    ///
1007    /// [`SliceSource`]: trait.SliceSource.html
1008    fn for_each<F>(&self, f: F)
1009    where
1010        F: for<'a> FnMut(&'a SliceSource<T>);
1011}
1012
1013impl<T, U> SliceSourceCollection<T> for U
1014where
1015    T: SliceLike + ?Sized,
1016    U: Array,
1017    <U as Array>::Item: SliceSource<T>,
1018{
1019    fn for_each<F>(&self, mut f: F)
1020    where
1021        F: for<'a> FnMut(&'a SliceSource<T>),
1022    {
1023        for source in self.as_slice() {
1024            f(source);
1025        }
1026    }
1027}
1028
1029impl<'b, T, U> SliceSourceCollection<T> for &'b [U]
1030where
1031    T: SliceLike + ?Sized,
1032    U: SliceSource<T>,
1033{
1034    fn for_each<F>(&self, mut f: F)
1035    where
1036        F: for<'a> FnMut(&'a SliceSource<T>),
1037    {
1038        for source in *self {
1039            f(source);
1040        }
1041    }
1042}
1043
1044#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1045impl<T, U> SliceSourceCollection<T> for Box<[U]>
1046where
1047    T: SliceLike + ?Sized,
1048    U: SliceSource<T>,
1049{
1050    fn for_each<F>(&self, mut f: F)
1051    where
1052        F: for<'a> FnMut(&'a SliceSource<T>),
1053    {
1054        for source in &**self {
1055            f(source);
1056        }
1057    }
1058}
1059
1060#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1061impl<T, U> SliceSourceCollection<T> for Vec<U>
1062where
1063    T: SliceLike + ?Sized,
1064    U: SliceSource<T>,
1065{
1066    fn for_each<F>(&self, mut f: F)
1067    where
1068        F: for<'a> FnMut(&'a SliceSource<T>),
1069    {
1070        for source in self {
1071            f(source);
1072        }
1073    }
1074}
1075
1076#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1077impl<'b, T, U> SliceSourceCollection<T> for &'b Box<[U]>
1078where
1079    T: SliceLike + ?Sized,
1080    U: SliceSource<T>,
1081{
1082    fn for_each<F>(&self, mut f: F)
1083    where
1084        F: for<'a> FnMut(&'a SliceSource<T>),
1085    {
1086        for source in &***self {
1087            f(source);
1088        }
1089    }
1090}
1091
1092#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1093impl<'b, T, U> SliceSourceCollection<T> for &'b Vec<U>
1094where
1095    T: SliceLike + ?Sized,
1096    U: SliceSource<T>,
1097{
1098    fn for_each<F>(&self, mut f: F)
1099    where
1100        F: for<'a> FnMut(&'a SliceSource<T>),
1101    {
1102        for source in *self {
1103            f(source);
1104        }
1105    }
1106}
1107
1108/// Subtrait of [`SliceSourceCollection`] for taking ownership of the contents
1109/// of a collection of slice sources.
1110///
1111/// [`SliceSourceCollection`]: trait.SliceSourceCollection.html
1112pub trait SliceMoveSourceCollection<T>: SliceSourceCollection<T>
1113where
1114    T: SliceLike + ?Sized,
1115{
1116    /// Calls a closure for each item in all [`SliceSource`] objects of this
1117    /// collection in sequence, consuming the collection.
1118    ///
1119    /// # Examples
1120    ///
1121    /// ```
1122    /// use scratchpad::SliceMoveSourceCollection;
1123    ///
1124    /// let collection = ([1, 2, 3], [4], [5, 6]);
1125    ///
1126    /// let mut out = Vec::new();
1127    /// collection.move_all_elements(|x| out.push(x * 2));
1128    /// assert_eq!(*out, [2, 4, 6, 8, 10, 12]);
1129    /// ```
1130    ///
1131    /// [`SliceSource`]: trait.SliceSource.html
1132    fn move_all_elements<F>(self, f: F)
1133    where
1134        Self: Sized,
1135        F: FnMut(<T as SliceLike>::Element);
1136}
1137
1138impl<T, U> SliceMoveSourceCollection<T> for U
1139where
1140    T: SliceLike + ?Sized,
1141    U: Array,
1142    <U as Array>::Item: SliceMoveSource<T>,
1143{
1144    fn move_all_elements<F>(self, mut f: F)
1145    where
1146        F: FnMut(<T as SliceLike>::Element),
1147    {
1148        for source in ArrayIter::new(self) {
1149            source.move_elements(&mut f);
1150        }
1151    }
1152}
1153
1154impl<'b, T, U> SliceMoveSourceCollection<T> for &'b [U]
1155where
1156    T: SliceLike + ?Sized,
1157    <T as SliceLike>::Element: Copy,
1158    U: SliceSource<T>,
1159{
1160    fn move_all_elements<F>(self, mut f: F)
1161    where
1162        F: FnMut(<T as SliceLike>::Element),
1163    {
1164        for source in self {
1165            for item in source.as_slice_like().as_element_slice() {
1166                f(*item);
1167            }
1168        }
1169    }
1170}
1171
1172#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1173impl<T, U> SliceMoveSourceCollection<T> for Box<[U]>
1174where
1175    T: SliceLike + ?Sized,
1176    U: SliceMoveSource<T>,
1177{
1178    fn move_all_elements<F>(self, mut f: F)
1179    where
1180        F: FnMut(<T as SliceLike>::Element),
1181    {
1182        for source in self.into_vec() {
1183            source.move_elements(&mut f);
1184        }
1185    }
1186}
1187
1188#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1189impl<T, U> SliceMoveSourceCollection<T> for Vec<U>
1190where
1191    T: SliceLike + ?Sized,
1192    U: SliceMoveSource<T>,
1193{
1194    fn move_all_elements<F>(self, mut f: F)
1195    where
1196        F: FnMut(<T as SliceLike>::Element),
1197    {
1198        for source in self {
1199            source.move_elements(&mut f);
1200        }
1201    }
1202}
1203
1204#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1205impl<'b, T, U> SliceMoveSourceCollection<T> for &'b Box<[U]>
1206where
1207    T: SliceLike + ?Sized,
1208    <T as SliceLike>::Element: Copy,
1209    U: SliceSource<T>,
1210{
1211    fn move_all_elements<F>(self, mut f: F)
1212    where
1213        F: FnMut(<T as SliceLike>::Element),
1214    {
1215        for source in &**self {
1216            for item in source.as_slice_like().as_element_slice() {
1217                f(*item);
1218            }
1219        }
1220    }
1221}
1222
1223#[cfg(any(feature = "std", feature = "alloc", feature = "unstable"))]
1224impl<'b, T, U> SliceMoveSourceCollection<T> for &'b Vec<U>
1225where
1226    T: SliceLike + ?Sized,
1227    <T as SliceLike>::Element: Copy,
1228    U: SliceSource<T>,
1229{
1230    fn move_all_elements<F>(self, mut f: F)
1231    where
1232        F: FnMut(<T as SliceLike>::Element),
1233    {
1234        for source in self {
1235            for item in source.as_slice_like().as_element_slice() {
1236                f(*item);
1237            }
1238        }
1239    }
1240}
1241
1242/// Macro for generating trait implementations for tuples.
1243macro_rules! generate_tuple_trait_impls {
1244    ($($name:ident,)+) => {
1245        impl<T, $($name,)*> SliceSourceCollection<T> for ($($name,)*)
1246        where
1247            T: SliceLike + ?Sized,
1248            $($name: SliceSource<T>,)*
1249        {
1250            #[allow(non_snake_case)]
1251            fn for_each<F>(&self, mut f: F)
1252            where
1253                F: for<'a> FnMut(&'a SliceSource<T>)
1254            {
1255                let ($(ref $name,)*) = *self;
1256                $(
1257                    f($name);
1258                )*
1259            }
1260        }
1261
1262        #[allow(non_snake_case)]
1263        impl<'b, T, $($name,)*> SliceSourceCollection<T> for &'b ($($name,)*)
1264        where
1265            T: SliceLike + ?Sized,
1266            $($name: SliceSource<T>,)*
1267        {
1268            #[allow(non_snake_case)]
1269            fn for_each<F>(&self, mut f: F)
1270            where
1271                F: for<'a> FnMut(&'a SliceSource<T>)
1272            {
1273                let ($(ref $name,)*) = **self;
1274                $(
1275                    f($name);
1276                )*
1277            }
1278        }
1279
1280        impl<T, $($name,)*> SliceMoveSourceCollection<T> for ($($name,)*)
1281        where
1282            T: SliceLike + ?Sized,
1283            $($name: SliceMoveSource<T>,)*
1284        {
1285            #[allow(non_snake_case)]
1286            fn move_all_elements<F>(self, mut f: F)
1287            where
1288                F: FnMut(<T as SliceLike>::Element),
1289            {
1290                let ($($name,)*) = self;
1291                $(
1292                    $name.move_elements(&mut f);
1293                )*
1294            }
1295        }
1296
1297        #[allow(non_snake_case)]
1298        impl<'b, T, $($name,)*> SliceMoveSourceCollection<T>
1299            for &'b ($($name,)*)
1300        where
1301            T: SliceLike + ?Sized,
1302            <T as SliceLike>::Element: Copy,
1303            $($name: SliceSource<T>,)*
1304        {
1305            #[allow(non_snake_case)]
1306            fn move_all_elements<F>(self, mut f: F)
1307            where
1308                F: FnMut(<T as SliceLike>::Element),
1309            {
1310                let ($(ref $name,)*) = *self;
1311                $(
1312                    for item in $name.as_slice_like().as_element_slice() {
1313                        f(*item);
1314                    }
1315                )*
1316            }
1317        }
1318
1319        generate_tuple_trait_impls!([REDUCE] $($name,)*);
1320    };
1321
1322    () => {};
1323
1324    ([REDUCE] $name:ident, $($remaining:ident,)*) => {
1325        generate_tuple_trait_impls!($($remaining,)*);
1326    }
1327}
1328
1329generate_tuple_trait_impls!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,);
1330
1331/// Macro for generating trait implementations for static arrays.
1332macro_rules! generate_array_trait_impls {
1333    ($size:expr) => {
1334        unsafe impl<T> Array for [T; $size]
1335        where
1336            T: Sized,
1337        {
1338            type Item = T;
1339
1340            #[inline]
1341            fn as_slice(&self) -> &[T] {
1342                &self[..]
1343            }
1344
1345            #[inline]
1346            fn as_mut_slice(&mut self) -> &mut [T] {
1347                &mut self[..]
1348            }
1349        }
1350
1351        unsafe impl<T> IntoMutSliceLikePtr<[T]> for [T; $size] {
1352            // LINT: Despite the notation, `ptr` doesn't actually get
1353            //       dereferenced by this function (only the pointer value
1354            //       itself is ever read), so the lint error can be ignored.
1355            #[cfg_attr(feature = "cargo-clippy", allow(clippy::not_unsafe_ptr_arg_deref))]
1356            #[inline]
1357            fn into_mut_slice_like_ptr(ptr: *mut [T; $size]) -> *mut [T] {
1358                unsafe { &mut (*ptr)[..] }
1359            }
1360        }
1361    };
1362
1363    ($size:expr, $($other:tt)*) => {
1364        generate_array_trait_impls!($size);
1365        generate_array_trait_impls!($($other)*);
1366    };
1367
1368    () => {};
1369}
1370
1371generate_array_trait_impls!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1372generate_array_trait_impls!(11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
1373generate_array_trait_impls!(21, 22, 23, 24, 25, 26, 27, 28, 29, 30);
1374generate_array_trait_impls!(31, 32, 33, 34, 35, 36, 37, 38, 39, 40);
1375generate_array_trait_impls!(41, 42, 43, 44, 45, 46, 47, 48, 49, 50);
1376generate_array_trait_impls!(51, 52, 53, 54, 55, 56, 57, 58, 59, 60);
1377generate_array_trait_impls!(61, 62, 63, 64);
1378generate_array_trait_impls!(0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000);
1379generate_array_trait_impls!(
1380    0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000
1381);
1382generate_array_trait_impls!(
1383    0x10_0000, 0x20_0000, 0x40_0000, 0x80_0000, 0x100_0000
1384);
1385generate_array_trait_impls!(0x200_0000, 0x400_0000, 0x800_0000, 0x1000_0000);
1386generate_array_trait_impls!(0x2000_0000, 0x4000_0000);