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);