1use core::{
61 borrow::Borrow,
62 cmp::Ordering,
63 fmt::{Debug, Display},
64 hash::{Hash, Hasher},
65 marker::PhantomData,
66 mem,
67 mem::ManuallyDrop,
68 ops::{Deref, DerefMut},
69 ptr::{slice_from_raw_parts_mut, NonNull},
70 slice,
71 str::{from_utf8_unchecked, from_utf8_unchecked_mut},
72};
73use thiserror::Error;
74
75#[derive(Error, Debug)]
84#[error("The length `{len}` was too long")]
85pub struct LenTooLong<T = ()> {
86 pub len: usize,
88 pub too_long: T,
90}
91
92impl<T> LenTooLong<T> {
93 pub fn forget(self) -> LenTooLong {
95 self.map(drop)
96 }
97
98 pub fn map<U>(self, with: impl FnOnce(T) -> U) -> LenTooLong<U> {
100 LenTooLong {
101 len: self.len,
102 too_long: with(self.too_long),
103 }
104 }
105}
106
107#[inline]
109pub fn try_into<A, B: TryFrom<A, Error = LenTooLong<A>>>(x: A) -> Result<B, LenTooLong> {
110 x.try_into().map_err(|e: LenTooLong<A>| e.forget())
111}
112
113macro_rules! ensure_len_fits {
119 ($thing:expr) => {
120 let Ok(_) = u32::try_from($thing.len()) else {
121 return Err(LenTooLong {
122 len: $thing.len(),
123 too_long: $thing,
124 });
125 };
126 };
127}
128
129#[inline]
131fn expect_fit<A, E, B: TryInto<A, Error = LenTooLong<E>>>(x: B) -> A {
132 x.try_into().map_err(|e| e.len).expect("length didn't fit in `u32`")
133}
134
135#[inline]
136fn into_box<T, U: Into<Box<[T]>>>(x: U) -> Box<[T]> {
137 x.into()
138}
139
140struct AssertU32<const N: usize>;
142impl<const N: usize> AssertU32<N> {
143 const OK: () = assert!(N <= u32::MAX as usize);
144}
145
146pub unsafe trait SafelyExchangeable<T> {}
159
160#[repr(packed)]
164struct SlimRawSlice<T> {
165 ptr: NonNull<T>,
167 len: u32,
169}
170
171impl<T> SlimRawSlice<T> {
172 #[inline]
174 fn dangling() -> Self {
175 let ptr = NonNull::dangling();
176 Self { len: 0, ptr }
177 }
178
179 #[inline]
185 fn cast<U: SafelyExchangeable<T>>(self) -> SlimRawSlice<U> {
186 SlimRawSlice {
187 ptr: self.ptr.cast(),
188 len: self.len,
189 }
190 }
191
192 #[inline]
194 fn split(self) -> (*mut T, usize) {
195 (self.ptr.as_ptr(), self.len as usize)
196 }
197
198 #[allow(clippy::needless_lifetimes)]
218 #[inline]
219 unsafe fn deref<'a>(&'a self) -> &'a [T] {
220 let (ptr, len) = self.split();
221 unsafe { slice::from_raw_parts(ptr, len) }
223 }
224
225 #[allow(clippy::needless_lifetimes)]
246 #[inline]
247 unsafe fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
248 let (ptr, len) = self.split();
249 unsafe { slice::from_raw_parts_mut(ptr, len) }
251 }
252
253 #[inline]
258 const unsafe fn from_len_ptr(len: usize, ptr: *mut T) -> Self {
259 let ptr = NonNull::new_unchecked(ptr);
261 let len = len as u32;
262 Self { ptr, len }
263 }
264}
265
266impl<T> Copy for SlimRawSlice<T> {}
267impl<T> Clone for SlimRawSlice<T> {
268 #[inline]
269 fn clone(&self) -> Self {
270 *self
271 }
272}
273
274pub use slim_slice_box::*;
279mod slim_slice_box {
280 use super::*;
284
285 #[repr(transparent)]
288 pub struct SlimSliceBox<T> {
289 raw: SlimRawSlice<T>,
293 owned: PhantomData<T>,
295 }
296
297 impl<T> Drop for SlimSliceBox<T> {
298 #[inline]
299 fn drop(&mut self) {
300 let raw = SlimRawSlice::dangling();
304 let owned = PhantomData;
305 let this = mem::replace(self, Self { raw, owned });
306
307 drop(into_box(this));
309 }
310 }
311
312 impl<T> SlimSliceBox<T> {
313 #[allow(clippy::boxed_local)]
319 #[inline]
320 pub unsafe fn from_boxed_unchecked(boxed: Box<[T]>) -> Self {
322 let len = boxed.len();
323 let ptr = Box::into_raw(boxed) as *mut T;
324 let raw = SlimRawSlice::from_len_ptr(len, ptr);
327 let owned = PhantomData;
328 Self { raw, owned }
329 }
330
331 #[allow(clippy::needless_lifetimes)]
333 #[inline]
334 pub fn shared_ref<'a>(&'a self) -> &'a SlimSlice<'a, T> {
335 unsafe { mem::transmute(self) }
338 }
339
340 #[allow(clippy::needless_lifetimes)]
342 #[inline]
343 pub fn exclusive_ref<'a>(&'a mut self) -> &'a mut SlimSliceMut<'a, T> {
344 unsafe { mem::transmute(self) }
348 }
349
350 #[inline]
354 pub fn map_safely_exchangeable<U: SafelyExchangeable<T>>(self) -> SlimSliceBox<U> {
355 SlimSliceBox {
359 raw: self.raw.cast(),
360 owned: PhantomData,
361 }
362 }
363 }
364
365 impl<T> From<SlimSliceBox<T>> for Box<[T]> {
366 #[inline]
367 fn from(slice: SlimSliceBox<T>) -> Self {
368 let slice = ManuallyDrop::new(slice);
369 let (ptr, len) = slice.raw.split();
370 unsafe { Box::from_raw(slice_from_raw_parts_mut(ptr, len)) }
383 }
384 }
385}
386
387unsafe impl<T: Send> Send for SlimSliceBox<T> {}
389
390unsafe impl<T: Sync> Sync for SlimSliceBox<T> {}
392
393impl<T> Deref for SlimSliceBox<T> {
394 type Target = [T];
395
396 #[inline]
397 fn deref(&self) -> &Self::Target {
398 self.shared_ref().deref()
399 }
400}
401
402impl<T> DerefMut for SlimSliceBox<T> {
403 #[inline]
404 fn deref_mut(&mut self) -> &mut Self::Target {
405 self.exclusive_ref().deref_mut()
406 }
407}
408
409impl<T> SlimSliceBox<T> {
410 #[inline]
414 pub fn from_boxed(boxed: Box<[T]>) -> Self {
415 expect_fit(boxed)
416 }
417
418 #[inline]
422 pub fn from_vec(vec: Vec<T>) -> Self {
423 Self::from_boxed(vec.into())
424 }
425
426 #[inline]
430 pub fn map<U>(self, by: impl FnMut(T) -> U) -> SlimSliceBox<U> {
431 let mapped = self.into_iter().map(by).collect::<Box<_>>();
432 unsafe { SlimSliceBox::from_boxed_unchecked(mapped) }
434 }
435
436 #[inline]
440 pub fn map_borrowed<U>(&self, by: impl FnMut(&T) -> U) -> SlimSliceBox<U> {
441 let mapped = self.iter().map(by).collect::<Box<_>>();
442 unsafe { SlimSliceBox::from_boxed_unchecked(mapped) }
444 }
445}
446
447impl<T> TryFrom<Box<[T]>> for SlimSliceBox<T> {
448 type Error = LenTooLong<Box<[T]>>;
449
450 #[inline]
451 fn try_from(boxed: Box<[T]>) -> Result<Self, Self::Error> {
452 ensure_len_fits!(boxed);
453 Ok(unsafe { Self::from_boxed_unchecked(boxed) })
455 }
456}
457
458impl<T> TryFrom<Vec<T>> for SlimSliceBox<T> {
459 type Error = LenTooLong<Vec<T>>;
460
461 #[inline]
462 fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
463 ensure_len_fits!(vec);
464 Ok(unsafe { Self::from_boxed_unchecked(vec.into_boxed_slice()) })
466 }
467}
468
469impl<T, const N: usize> From<[T; N]> for SlimSliceBox<T> {
470 #[inline]
471 fn from(arr: [T; N]) -> Self {
472 #[allow(clippy::let_unit_value)]
473 let () = AssertU32::<N>::OK;
474
475 unsafe { Self::from_boxed_unchecked(into_box(arr)) }
477 }
478}
479
480impl<T> From<SlimSliceBox<T>> for Vec<T> {
481 #[inline]
482 fn from(slice: SlimSliceBox<T>) -> Self {
483 into_box(slice).into()
484 }
485}
486
487impl<T: Debug> Debug for SlimSliceBox<T> {
488 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
489 Debug::fmt(self.deref(), f)
490 }
491}
492
493impl<T: Clone> Clone for SlimSliceBox<T> {
494 #[inline]
495 fn clone(&self) -> Self {
496 let mut vec = Vec::with_capacity(self.len());
499 vec.extend_from_slice(self);
500 unsafe { Self::from_boxed_unchecked(into_box(vec)) }
502 }
503}
504
505impl<R: Deref, T> PartialEq<R> for SlimSliceBox<T>
506where
507 [T]: PartialEq<R::Target>,
508{
509 #[inline]
510 fn eq(&self, other: &R) -> bool {
511 **self == **other
512 }
513}
514
515impl<T: Eq> Eq for SlimSliceBox<T> {}
516
517impl<R: Deref, T> PartialOrd<R> for SlimSliceBox<T>
518where
519 [T]: PartialOrd<R::Target>,
520{
521 #[inline]
522 fn partial_cmp(&self, other: &R) -> Option<Ordering> {
523 (**self).partial_cmp(&**other)
524 }
525}
526
527impl<T: Ord> Ord for SlimSliceBox<T> {
528 #[inline]
529 fn cmp(&self, other: &Self) -> Ordering {
530 (**self).cmp(&**other)
531 }
532}
533
534impl<T: Hash> Hash for SlimSliceBox<T> {
535 #[inline]
536 fn hash<H: Hasher>(&self, state: &mut H) {
537 Hash::hash(&**self, state)
538 }
539}
540
541impl<T> IntoIterator for SlimSliceBox<T> {
542 type Item = T;
543 type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
544 #[inline]
545 fn into_iter(self) -> Self::IntoIter {
546 Vec::from(self).into_iter()
547 }
548}
549
550pub struct SlimSliceBoxCollected<T> {
554 pub inner: Result<SlimSliceBox<T>, LenTooLong<Vec<T>>>,
556}
557
558impl<T: Debug> SlimSliceBoxCollected<T> {
559 #[inline]
560 pub fn unwrap(self) -> SlimSliceBox<T> {
561 self.inner.expect("number of elements overflowed `u32::MAX`")
562 }
563}
564
565impl<A> FromIterator<A> for SlimSliceBoxCollected<A> {
566 #[inline]
567 fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
568 let inner = iter.into_iter().collect::<Vec<_>>().try_into();
569 SlimSliceBoxCollected { inner }
570 }
571}
572
573pub struct SlimSmallSliceBox<T, const N: usize>(SlimSmallSliceBoxData<T, N>);
578
579enum SlimSmallSliceBoxData<T, const N: usize> {
583 Inline([T; N]),
585 Heap(SlimSliceBox<T>),
587}
588
589impl<T, const N: usize> From<[T; N]> for SlimSmallSliceBox<T, N> {
590 fn from(value: [T; N]) -> Self {
591 #[allow(clippy::let_unit_value)]
592 let () = AssertU32::<N>::OK;
593
594 Self(SlimSmallSliceBoxData::Inline(value))
595 }
596}
597
598impl<T, const N: usize> From<SlimSliceBox<T>> for SlimSmallSliceBox<T, N> {
599 fn from(value: SlimSliceBox<T>) -> Self {
600 Self(SlimSmallSliceBoxData::Heap(value))
601 }
602}
603
604impl<T, const N: usize> From<SlimSmallSliceBox<T, N>> for SlimSliceBox<T> {
605 fn from(SlimSmallSliceBox(value): SlimSmallSliceBox<T, N>) -> Self {
606 match value {
607 SlimSmallSliceBoxData::Inline(i) => i.into(),
608 SlimSmallSliceBoxData::Heap(h) => h,
609 }
610 }
611}
612
613impl<T, const N: usize> Deref for SlimSmallSliceBox<T, N> {
614 type Target = [T];
615 fn deref(&self) -> &Self::Target {
616 match &self.0 {
617 SlimSmallSliceBoxData::Inline(i) => i,
618 SlimSmallSliceBoxData::Heap(h) => h,
619 }
620 }
621}
622
623impl<T, const N: usize> DerefMut for SlimSmallSliceBox<T, N> {
624 fn deref_mut(&mut self) -> &mut Self::Target {
625 match &mut self.0 {
626 SlimSmallSliceBoxData::Inline(i) => i,
627 SlimSmallSliceBoxData::Heap(h) => h,
628 }
629 }
630}
631
632#[repr(transparent)]
639pub struct SlimStrBox {
640 raw: SlimSliceBox<u8>,
642}
643
644#[cfg(feature = "serde")]
645impl serde::Serialize for SlimStrBox {
646 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
647 s.serialize_str(self.deref())
648 }
649}
650
651impl SlimStrBox {
652 #[inline]
658 pub unsafe fn from_boxed_unchecked(boxed: Box<str>) -> Self {
659 let raw = unsafe { SlimSliceBox::from_boxed_unchecked(into_box(boxed)) };
661 Self { raw }
662 }
663
664 #[inline]
668 pub fn from_boxed(boxed: Box<str>) -> Self {
669 expect_fit(boxed)
670 }
671
672 #[inline]
676 pub fn from_string(str: String) -> Self {
677 Self::from_boxed(str.into())
678 }
679
680 #[allow(clippy::needless_lifetimes)]
682 #[inline]
683 pub fn shared_ref<'a>(&'a self) -> &'a SlimStr<'a> {
684 unsafe { mem::transmute(self.raw.shared_ref()) }
688 }
689
690 #[allow(clippy::needless_lifetimes)]
692 #[inline]
693 pub fn exclusive_ref<'a>(&'a mut self) -> &'a mut SlimStrMut<'a> {
694 unsafe { mem::transmute(self.raw.exclusive_ref()) }
698 }
699}
700
701impl Deref for SlimStrBox {
702 type Target = str;
703
704 #[inline]
705 fn deref(&self) -> &Self::Target {
706 self.shared_ref().deref()
707 }
708}
709
710impl DerefMut for SlimStrBox {
711 #[inline]
712 fn deref_mut(&mut self) -> &mut Self::Target {
713 self.exclusive_ref().deref_mut()
714 }
715}
716
717impl<const N: usize> From<NStr<N>> for SlimStrBox {
718 #[inline]
719 fn from(arr: NStr<N>) -> Self {
720 (&arr).into()
721 }
722}
723
724impl<const N: usize> From<&NStr<N>> for SlimStrBox {
725 #[inline]
726 fn from(arr: &NStr<N>) -> Self {
727 <SlimStr<'_>>::from(arr).into()
728 }
729}
730
731impl TryFrom<Box<str>> for SlimStrBox {
732 type Error = LenTooLong<Box<str>>;
733
734 #[inline]
735 fn try_from(boxed: Box<str>) -> Result<Self, Self::Error> {
736 ensure_len_fits!(boxed);
737 Ok(unsafe { Self::from_boxed_unchecked(boxed) })
739 }
740}
741
742impl TryFrom<String> for SlimStrBox {
743 type Error = LenTooLong<String>;
744
745 #[inline]
746 fn try_from(str: String) -> Result<Self, Self::Error> {
747 ensure_len_fits!(str);
748 Ok(unsafe { Self::from_boxed_unchecked(str.into_boxed_str()) })
750 }
751}
752
753impl<'a> TryFrom<&'a str> for SlimStrBox {
754 type Error = LenTooLong<&'a str>;
755
756 #[inline]
757 fn try_from(str: &'a str) -> Result<Self, Self::Error> {
758 str.try_into().map(|s: SlimStr<'_>| s.into())
759 }
760}
761
762impl From<SlimStrBox> for Box<str> {
763 #[inline]
764 fn from(str: SlimStrBox) -> Self {
765 let raw_box = into_box(str.raw);
766 unsafe { Box::from_raw(Box::into_raw(raw_box) as *mut str) }
768 }
769}
770
771impl From<SlimStrBox> for String {
772 #[inline]
773 fn from(str: SlimStrBox) -> Self {
774 <Box<str>>::from(str).into()
775 }
776}
777
778impl Debug for SlimStrBox {
779 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
780 Debug::fmt(self.deref(), f)
781 }
782}
783
784impl Display for SlimStrBox {
785 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
786 Display::fmt(self.deref(), f)
787 }
788}
789
790impl Clone for SlimStrBox {
791 #[inline]
792 fn clone(&self) -> Self {
793 Self { raw: self.raw.clone() }
794 }
795}
796
797impl<R: Deref> PartialEq<R> for SlimStrBox
798where
799 str: PartialEq<R::Target>,
800{
801 #[inline]
802 fn eq(&self, other: &R) -> bool {
803 self.deref() == other.deref()
804 }
805}
806
807impl Eq for SlimStrBox {}
808
809impl<R: Deref> PartialOrd<R> for SlimStrBox
810where
811 str: PartialOrd<R::Target>,
812{
813 #[inline]
814 fn partial_cmp(&self, other: &R) -> Option<Ordering> {
815 self.deref().partial_cmp(other.deref())
816 }
817}
818
819impl Ord for SlimStrBox {
820 #[inline]
821 fn cmp(&self, other: &Self) -> Ordering {
822 self.deref().cmp(other.deref())
823 }
824}
825
826impl Hash for SlimStrBox {
827 #[inline]
828 fn hash<H: Hasher>(&self, state: &mut H) {
829 Hash::hash(self.deref(), state)
830 }
831}
832
833impl Borrow<str> for SlimStrBox {
834 #[inline]
835 fn borrow(&self) -> &str {
836 self
837 }
838}
839
840#[allow(clippy::module_inception)]
845mod slim_slice {
846 use super::*;
847
848 #[repr(transparent)]
850 #[derive(Clone, Copy)]
851 pub struct SlimSlice<'a, T> {
852 raw: SlimRawSlice<T>,
854 covariant: PhantomData<&'a [T]>,
856 }
857
858 impl<'a, T> SlimSlice<'a, T> {
859 pub(super) const unsafe fn from_slice_unchecked(slice: &'a [T]) -> Self {
863 let len = slice.len();
864 let ptr = slice.as_ptr().cast_mut();
865 let raw = SlimRawSlice::from_len_ptr(len, ptr);
867 let covariant = PhantomData;
869 Self { raw, covariant }
870 }
871 }
872
873 impl<T> Deref for SlimSlice<'_, T> {
874 type Target = [T];
875
876 fn deref(&self) -> &Self::Target {
877 unsafe { self.raw.deref() }
882 }
883 }
884}
885pub use slim_slice::*;
886
887use crate::nstr::NStr;
888
889unsafe impl<T: Send + Sync> Send for SlimSlice<'_, T> {}
891
892unsafe impl<T: Sync> Sync for SlimSlice<'_, T> {}
894
895impl<T> SlimSlice<'_, T> {
896 #[inline]
900 pub fn try_map<U, E>(&self, by: impl FnMut(&T) -> Result<U, E>) -> Result<SlimSliceBox<U>, E> {
901 let mapped = self.iter().map(by).collect::<Result<_, _>>()?;
902 Ok(unsafe { SlimSliceBox::from_boxed_unchecked(mapped) })
904 }
905}
906
907impl<T: Debug> Debug for SlimSlice<'_, T> {
908 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
909 Debug::fmt(self.deref(), f)
910 }
911}
912
913impl<T: Hash> Hash for SlimSlice<'_, T> {
914 #[inline]
915 fn hash<H: Hasher>(&self, state: &mut H) {
916 Hash::hash(self.deref(), state)
917 }
918}
919
920impl<T: Eq> Eq for SlimSlice<'_, T> {}
921impl<T: PartialEq> PartialEq for SlimSlice<'_, T> {
922 #[inline]
923 fn eq(&self, other: &Self) -> bool {
924 self.deref() == other.deref()
925 }
926}
927impl<T: PartialEq> PartialEq<[T]> for SlimSlice<'_, T> {
928 #[inline]
929 fn eq(&self, other: &[T]) -> bool {
930 self.deref() == other
931 }
932}
933
934impl<T: Ord> Ord for SlimSlice<'_, T> {
935 #[inline]
936 fn cmp(&self, other: &Self) -> Ordering {
937 self.deref().cmp(other)
938 }
939}
940impl<T: PartialOrd> PartialOrd for SlimSlice<'_, T> {
941 #[inline]
942 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
943 self.deref().partial_cmp(other.deref())
944 }
945}
946impl<T: PartialOrd> PartialOrd<[T]> for SlimSlice<'_, T> {
947 #[inline]
948 fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
949 self.deref().partial_cmp(other)
950 }
951}
952
953impl<T: Clone> From<&SlimSlice<'_, T>> for SlimSliceBox<T> {
954 #[inline]
955 fn from(slice: &SlimSlice<'_, T>) -> Self {
956 let boxed = into_box(slice.deref());
957 unsafe { Self::from_boxed_unchecked(boxed) }
959 }
960}
961impl<T: Clone> From<&SlimSlice<'_, T>> for Box<[T]> {
962 #[inline]
963 fn from(slice: &SlimSlice<'_, T>) -> Self {
964 slice.deref().into()
965 }
966}
967impl<T: Clone> From<&SlimSlice<'_, T>> for Vec<T> {
968 #[inline]
969 fn from(slice: &SlimSlice<'_, T>) -> Self {
970 slice.deref().into()
971 }
972}
973
974impl<T: Clone> From<SlimSlice<'_, T>> for SlimSliceBox<T> {
975 #[inline]
976 fn from(slice: SlimSlice<'_, T>) -> Self {
977 (&slice).into()
978 }
979}
980impl<T: Clone> From<SlimSlice<'_, T>> for Box<[T]> {
981 #[inline]
982 fn from(slice: SlimSlice<'_, T>) -> Self {
983 slice.deref().into()
984 }
985}
986impl<T: Clone> From<SlimSlice<'_, T>> for Vec<T> {
987 #[inline]
988 fn from(slice: SlimSlice<'_, T>) -> Self {
989 slice.deref().into()
990 }
991}
992
993impl<'a, T> TryFrom<&'a [T]> for SlimSlice<'a, T> {
994 type Error = LenTooLong<&'a [T]>;
995
996 #[inline]
997 fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
998 ensure_len_fits!(slice);
999 Ok(unsafe { Self::from_slice_unchecked(slice) })
1001 }
1002}
1003
1004#[inline]
1008pub fn from_slice<T>(s: &[T]) -> SlimSlice<'_, T> {
1009 expect_fit(s)
1010}
1011
1012#[repr(transparent)]
1018pub struct SlimSliceMut<'a, T> {
1019 raw: SlimRawSlice<T>,
1021 invariant: PhantomData<&'a mut [T]>,
1023}
1024
1025unsafe impl<T: Send> Send for SlimSliceMut<'_, T> {}
1027
1028unsafe impl<T: Sync> Sync for SlimSliceMut<'_, T> {}
1030
1031impl<'a, T> SlimSliceMut<'a, T> {
1032 #[inline]
1034 pub fn shared(&'a self) -> &'a SlimSlice<'a, T> {
1035 unsafe { mem::transmute(self) }
1038 }
1039
1040 #[inline]
1044 unsafe fn from_slice_unchecked(slice: &'a mut [T]) -> Self {
1045 let raw = SlimRawSlice::from_len_ptr(slice.len(), slice.as_mut_ptr());
1047 let invariant = PhantomData;
1050 Self { raw, invariant }
1051 }
1052}
1053
1054impl<T> Deref for SlimSliceMut<'_, T> {
1055 type Target = [T];
1056
1057 #[inline]
1058 fn deref(&self) -> &Self::Target {
1059 self.shared().deref()
1060 }
1061}
1062
1063impl<T> DerefMut for SlimSliceMut<'_, T> {
1064 #[inline]
1065 fn deref_mut(&mut self) -> &mut Self::Target {
1066 unsafe { self.raw.deref_mut() }
1072 }
1073}
1074
1075impl<T: Debug> Debug for SlimSliceMut<'_, T> {
1076 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1077 Debug::fmt(self.deref(), f)
1078 }
1079}
1080
1081impl<T: Hash> Hash for SlimSliceMut<'_, T> {
1082 #[inline]
1083 fn hash<H: Hasher>(&self, state: &mut H) {
1084 Hash::hash(self.deref(), state)
1085 }
1086}
1087
1088impl<T: Eq> Eq for SlimSliceMut<'_, T> {}
1089impl<T: PartialEq> PartialEq for SlimSliceMut<'_, T> {
1090 #[inline]
1091 fn eq(&self, other: &Self) -> bool {
1092 self.deref() == other.deref()
1093 }
1094}
1095impl<T: PartialEq> PartialEq<[T]> for SlimSliceMut<'_, T> {
1096 #[inline]
1097 fn eq(&self, other: &[T]) -> bool {
1098 self.deref() == other
1099 }
1100}
1101
1102impl<T: Ord> Ord for SlimSliceMut<'_, T> {
1103 #[inline]
1104 fn cmp(&self, other: &Self) -> Ordering {
1105 self.deref().cmp(other)
1106 }
1107}
1108impl<T: PartialOrd> PartialOrd for SlimSliceMut<'_, T> {
1109 #[inline]
1110 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1111 self.deref().partial_cmp(other.deref())
1112 }
1113}
1114impl<T: PartialOrd> PartialOrd<[T]> for SlimSliceMut<'_, T> {
1115 #[inline]
1116 fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
1117 self.deref().partial_cmp(other)
1118 }
1119}
1120
1121impl<T: Clone> From<&SlimSliceMut<'_, T>> for SlimSliceBox<T> {
1122 #[inline]
1123 fn from(slice: &SlimSliceMut<'_, T>) -> Self {
1124 unsafe { Self::from_boxed_unchecked(into_box(slice.deref())) }
1126 }
1127}
1128impl<T: Clone> From<&SlimSliceMut<'_, T>> for Box<[T]> {
1129 #[inline]
1130 fn from(slice: &SlimSliceMut<'_, T>) -> Self {
1131 slice.deref().into()
1132 }
1133}
1134impl<T: Clone> From<&SlimSliceMut<'_, T>> for Vec<T> {
1135 #[inline]
1136 fn from(slice: &SlimSliceMut<'_, T>) -> Self {
1137 slice.deref().into()
1138 }
1139}
1140
1141impl<T: Clone> From<SlimSliceMut<'_, T>> for SlimSliceBox<T> {
1142 #[inline]
1143 fn from(slice: SlimSliceMut<'_, T>) -> Self {
1144 (&slice).into()
1145 }
1146}
1147impl<T: Clone> From<SlimSliceMut<'_, T>> for Box<[T]> {
1148 #[inline]
1149 fn from(slice: SlimSliceMut<'_, T>) -> Self {
1150 slice.deref().into()
1151 }
1152}
1153impl<T: Clone> From<SlimSliceMut<'_, T>> for Vec<T> {
1154 #[inline]
1155 fn from(slice: SlimSliceMut<'_, T>) -> Self {
1156 slice.deref().into()
1157 }
1158}
1159
1160impl<'a, T> TryFrom<&'a mut [T]> for SlimSliceMut<'a, T> {
1161 type Error = LenTooLong<&'a mut [T]>;
1162
1163 #[inline]
1164 fn try_from(slice: &'a mut [T]) -> Result<Self, Self::Error> {
1165 ensure_len_fits!(slice);
1166 Ok(unsafe { Self::from_slice_unchecked(slice) })
1168 }
1169}
1170
1171#[inline]
1175pub fn from_slice_mut<T>(s: &mut [T]) -> SlimSliceMut<'_, T> {
1176 expect_fit(s)
1177}
1178
1179#[repr(transparent)]
1185#[derive(Clone, Copy)]
1186pub struct SlimStr<'a> {
1187 raw: SlimSlice<'a, u8>,
1189}
1190
1191impl<'a> SlimStr<'a> {
1192 #[inline]
1198 const unsafe fn from_str_unchecked(s: &'a str) -> Self {
1199 let raw = unsafe { SlimSlice::from_slice_unchecked(s.as_bytes()) };
1201 Self { raw }
1203 }
1204}
1205
1206impl Deref for SlimStr<'_> {
1207 type Target = str;
1208
1209 #[inline]
1210 fn deref(&self) -> &Self::Target {
1211 unsafe { from_utf8_unchecked(self.raw.deref()) }
1213 }
1214}
1215
1216impl Debug for SlimStr<'_> {
1217 #[inline]
1218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1219 Debug::fmt(self.deref(), f)
1220 }
1221}
1222
1223impl Display for SlimStr<'_> {
1224 #[inline]
1225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1226 Display::fmt(self.deref(), f)
1227 }
1228}
1229
1230impl Hash for SlimStr<'_> {
1231 #[inline]
1232 fn hash<H: Hasher>(&self, state: &mut H) {
1233 Hash::hash(self.deref(), state)
1234 }
1235}
1236
1237impl Eq for SlimStr<'_> {}
1238impl PartialEq for SlimStr<'_> {
1239 #[inline]
1240 fn eq(&self, other: &Self) -> bool {
1241 self.deref() == other.deref()
1242 }
1243}
1244impl PartialEq<str> for SlimStr<'_> {
1245 #[inline]
1246 fn eq(&self, other: &str) -> bool {
1247 self.deref() == other
1248 }
1249}
1250
1251impl Ord for SlimStr<'_> {
1252 #[inline]
1253 fn cmp(&self, other: &Self) -> Ordering {
1254 self.deref().cmp(other)
1255 }
1256}
1257impl PartialOrd for SlimStr<'_> {
1258 #[inline]
1259 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1260 Some(self.cmp(other))
1261 }
1262}
1263impl PartialOrd<str> for SlimStr<'_> {
1264 #[inline]
1265 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
1266 self.deref().partial_cmp(other)
1267 }
1268}
1269
1270impl From<&SlimStr<'_>> for SlimStrBox {
1271 #[inline]
1272 fn from(slice: &SlimStr<'_>) -> Self {
1273 (*slice).into()
1274 }
1275}
1276impl From<&SlimStr<'_>> for Box<str> {
1277 #[inline]
1278 fn from(slice: &SlimStr<'_>) -> Self {
1279 slice.deref().into()
1280 }
1281}
1282impl From<&SlimStr<'_>> for String {
1283 #[inline]
1284 fn from(slice: &SlimStr<'_>) -> Self {
1285 slice.deref().into()
1286 }
1287}
1288
1289impl From<SlimStr<'_>> for SlimStrBox {
1290 #[inline]
1291 fn from(slice: SlimStr<'_>) -> Self {
1292 Self { raw: slice.raw.into() }
1294 }
1295}
1296impl From<SlimStr<'_>> for Box<str> {
1297 #[inline]
1298 fn from(slice: SlimStr<'_>) -> Self {
1299 slice.deref().into()
1300 }
1301}
1302impl From<SlimStr<'_>> for String {
1303 #[inline]
1304 fn from(slice: SlimStr<'_>) -> Self {
1305 slice.deref().into()
1306 }
1307}
1308
1309impl<'a, const N: usize> From<&'a NStr<N>> for SlimStr<'a> {
1310 #[inline]
1311 fn from(arr: &'a NStr<N>) -> Self {
1312 #[allow(clippy::let_unit_value)]
1313 let () = AssertU32::<N>::OK;
1314
1315 unsafe { Self::from_str_unchecked(arr) }
1317 }
1318}
1319impl<'a> TryFrom<&'a str> for SlimStr<'a> {
1320 type Error = LenTooLong<&'a str>;
1321
1322 #[inline]
1323 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
1324 ensure_len_fits!(s);
1325 Ok(unsafe { Self::from_str_unchecked(s) })
1327 }
1328}
1329
1330#[inline]
1334pub const fn from_str(s: &str) -> SlimStr<'_> {
1335 if s.len() > u32::MAX as usize {
1336 panic!("length didn't fit in `u32`");
1337 }
1338
1339 unsafe { SlimStr::from_str_unchecked(s) }
1341}
1342
1343#[inline]
1347pub fn from_string(s: &str) -> SlimStrBox {
1348 from_str(s).into()
1349}
1350
1351#[repr(transparent)]
1357pub struct SlimStrMut<'a> {
1358 raw: SlimSliceMut<'a, u8>,
1360}
1361
1362impl<'a> SlimStrMut<'a> {
1363 #[inline]
1369 unsafe fn from_str_unchecked(s: &'a mut str) -> Self {
1370 let raw = unsafe { SlimSliceMut::from_slice_unchecked(s.as_bytes_mut()) };
1372 Self { raw }
1374 }
1375}
1376
1377impl Deref for SlimStrMut<'_> {
1378 type Target = str;
1379
1380 #[inline]
1381 fn deref(&self) -> &Self::Target {
1382 unsafe { from_utf8_unchecked(self.raw.deref()) }
1384 }
1385}
1386
1387impl DerefMut for SlimStrMut<'_> {
1388 #[inline]
1389 fn deref_mut(&mut self) -> &mut Self::Target {
1390 unsafe { from_utf8_unchecked_mut(self.raw.deref_mut()) }
1392 }
1393}
1394
1395impl Debug for SlimStrMut<'_> {
1396 #[inline]
1397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1398 Debug::fmt(self.deref(), f)
1399 }
1400}
1401
1402impl Display for SlimStrMut<'_> {
1403 #[inline]
1404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1405 Display::fmt(self.deref(), f)
1406 }
1407}
1408
1409impl Hash for SlimStrMut<'_> {
1410 #[inline]
1411 fn hash<H: Hasher>(&self, state: &mut H) {
1412 Hash::hash(self.deref(), state)
1413 }
1414}
1415
1416impl Eq for SlimStrMut<'_> {}
1417impl PartialEq for SlimStrMut<'_> {
1418 #[inline]
1419 fn eq(&self, other: &Self) -> bool {
1420 self.deref() == other.deref()
1421 }
1422}
1423impl PartialEq<str> for SlimStrMut<'_> {
1424 #[inline]
1425 fn eq(&self, other: &str) -> bool {
1426 self.deref() == other
1427 }
1428}
1429
1430impl Ord for SlimStrMut<'_> {
1431 #[inline]
1432 fn cmp(&self, other: &Self) -> Ordering {
1433 self.deref().cmp(other)
1434 }
1435}
1436impl PartialOrd for SlimStrMut<'_> {
1437 #[inline]
1438 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1439 Some(self.cmp(other))
1440 }
1441}
1442impl PartialOrd<str> for SlimStrMut<'_> {
1443 #[inline]
1444 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
1445 self.deref().partial_cmp(other)
1446 }
1447}
1448
1449impl From<&SlimStrMut<'_>> for SlimStrBox {
1450 #[inline]
1451 fn from(slice: &SlimStrMut<'_>) -> Self {
1452 Self {
1454 raw: (&slice.raw).into(),
1455 }
1456 }
1457}
1458impl From<&SlimStrMut<'_>> for Box<str> {
1459 #[inline]
1460 fn from(slice: &SlimStrMut<'_>) -> Self {
1461 slice.deref().into()
1462 }
1463}
1464impl From<&SlimStrMut<'_>> for String {
1465 #[inline]
1466 fn from(slice: &SlimStrMut<'_>) -> Self {
1467 slice.deref().into()
1468 }
1469}
1470
1471impl From<SlimStrMut<'_>> for SlimStrBox {
1472 #[inline]
1473 fn from(slice: SlimStrMut<'_>) -> Self {
1474 (&slice).into()
1475 }
1476}
1477impl From<SlimStrMut<'_>> for Box<str> {
1478 #[inline]
1479 fn from(slice: SlimStrMut<'_>) -> Self {
1480 slice.deref().into()
1481 }
1482}
1483impl From<SlimStrMut<'_>> for String {
1484 #[inline]
1485 fn from(slice: SlimStrMut<'_>) -> Self {
1486 slice.deref().into()
1487 }
1488}
1489
1490impl<'a, const N: usize> From<&'a mut NStr<N>> for SlimStrMut<'a> {
1491 #[inline]
1492 fn from(arr: &'a mut NStr<N>) -> Self {
1493 #[allow(clippy::let_unit_value)]
1494 let () = AssertU32::<N>::OK;
1495
1496 unsafe { Self::from_str_unchecked(arr) }
1498 }
1499}
1500impl<'a> TryFrom<&'a mut str> for SlimStrMut<'a> {
1501 type Error = LenTooLong<&'a mut str>;
1502
1503 #[inline]
1504 fn try_from(slice: &'a mut str) -> Result<Self, Self::Error> {
1505 ensure_len_fits!(slice);
1506 Ok(unsafe { Self::from_str_unchecked(slice) })
1508 }
1509}
1510
1511#[inline]
1515pub fn from_str_mut(s: &mut str) -> SlimStrMut<'_> {
1516 expect_fit(s)
1517}
1518
1519#[cfg(test)]
1520mod tests {
1521 use std::hash::BuildHasher;
1522
1523 use super::*;
1524 use crate::map::DefaultHashBuilder;
1525 use crate::nstr;
1526
1527 fn hash_of<T: Hash>(x: T) -> u64 {
1528 DefaultHashBuilder::default().hash_one(&x)
1529 }
1530
1531 fn hash_properties<T>(a: &T, b: &T, a_deref: &T::Target, b_deref: &T::Target)
1532 where
1533 T: Hash + Debug + Deref,
1534 <T as Deref>::Target: Hash,
1535 {
1536 assert_eq!(hash_of(a), hash_of(a_deref));
1537 assert_eq!(hash_of(b), hash_of(b_deref));
1538 assert_ne!(hash_of(a), hash_of(b));
1539 }
1540
1541 fn ord_properties<T>(a: &T, b: &T, a_deref: &T::Target, b_deref: &T::Target)
1542 where
1543 T: Ord + Debug + Deref + PartialOrd<<T as Deref>::Target>,
1544 {
1545 assert_eq!(a.partial_cmp(b), Some(Ordering::Less));
1546 assert_eq!(b.partial_cmp(a), Some(Ordering::Greater));
1547 assert_eq!(a.partial_cmp(a), Some(Ordering::Equal));
1548 assert_eq!(b.partial_cmp(b), Some(Ordering::Equal));
1549 assert_eq!(a.partial_cmp(b_deref), Some(Ordering::Less));
1550 assert_eq!(b.partial_cmp(a_deref), Some(Ordering::Greater));
1551 assert_eq!(a.partial_cmp(a_deref), Some(Ordering::Equal));
1552 assert_eq!(b.partial_cmp(b_deref), Some(Ordering::Equal));
1553
1554 assert_eq!(a.cmp(b), Ordering::Less);
1555 assert_eq!(b.cmp(a), Ordering::Greater);
1556 assert_eq!(a.cmp(a), Ordering::Equal);
1557 assert_eq!(b.cmp(b), Ordering::Equal);
1558 }
1559
1560 #[allow(clippy::eq_op)]
1561 fn eq_properties<T>(a: &T, b: &T, a_deref: &T::Target, b_deref: &T::Target)
1562 where
1563 T: Eq + Debug + Deref + PartialEq<<T as Deref>::Target>,
1564 {
1565 assert!(a != b);
1566 assert!(b != a);
1567 assert_eq!(a, a);
1568 assert!(a != b_deref);
1569 assert!(a == a_deref);
1570 assert!(b != a_deref);
1571 assert!(b == b_deref);
1572 }
1573
1574 fn debug_properties<T: Debug, U: ?Sized + Debug>(a: &T, b: &T, a_cmp: &U, b_cmp: &U) {
1575 assert_eq!(format!("{:?}", a), format!("{:?}", a_cmp));
1576 assert_eq!(format!("{:?}", b), format!("{:?}", b_cmp));
1577 }
1578
1579 fn display_properties<T: Debug + Display, U: ?Sized + Display>(a: &T, b: &T, a_cmp: &U, b_cmp: &U) {
1580 assert_eq!(a.to_string(), a_cmp.to_string());
1581 assert_eq!(b.to_string(), b_cmp.to_string());
1582 }
1583
1584 fn general_properties<T, U>(a: &T, b: &T, a_deref: &U, b_deref: &U)
1585 where
1586 T: Deref<Target = U> + Debug + Eq + PartialEq<U> + PartialOrd<U> + Ord + Hash,
1587 U: ?Sized + Debug + Eq + Ord + Hash,
1588 {
1589 eq_properties(a, b, a_deref, b_deref);
1590 ord_properties(a, b, a_deref, b_deref);
1591 hash_properties(a, b, a_deref, b_deref);
1592 debug_properties(a, b, a_deref, b_deref);
1593 }
1594
1595 const TEST_STR: &str = "foo";
1596 const TEST_STR2: &str = "fop";
1597 const TEST_SLICE: &[u8] = TEST_STR.as_bytes();
1598 const TEST_SLICE2: &[u8] = TEST_STR2.as_bytes();
1599
1600 fn test_strings() -> [String; 2] {
1601 [TEST_STR.to_string(), TEST_STR2.to_string()]
1602 }
1603
1604 fn test_slices() -> [Vec<u8>; 2] {
1605 [TEST_SLICE.to_owned(), TEST_SLICE2.to_owned()]
1606 }
1607
1608 fn various_boxed_slices() -> [[SlimSliceBox<u8>; 2]; 5] {
1609 [
1610 test_slices().map(SlimSliceBox::from_vec),
1611 test_slices().map(Box::from).map(SlimSliceBox::from_boxed),
1612 test_slices().map(|s| SlimSliceBox::try_from(s).unwrap()),
1613 test_slices().map(|s| SlimSliceBox::try_from(s.into_boxed_slice()).unwrap()),
1614 test_slices().map(|s| SlimSliceBox::from(<[u8; 3]>::try_from(s).unwrap())),
1615 ]
1616 }
1617
1618 fn various_boxed_strs() -> [[SlimStrBox; 2]; 7] {
1619 [
1620 [nstr!("foo"), nstr!("fop")],
1621 test_strings().map(|s| from_string(&s)),
1622 test_strings().map(SlimStrBox::from_string),
1623 test_strings().map(Box::from).map(SlimStrBox::from_boxed),
1624 test_strings().map(|s| SlimStrBox::try_from(s).unwrap()),
1625 test_strings().map(|s| SlimStrBox::try_from(s.into_boxed_str()).unwrap()),
1626 test_strings().map(|s| SlimStrBox::try_from(s.deref()).unwrap()),
1627 ]
1628 }
1629
1630 fn assert_str_mut_properties(s1: &mut SlimStrMut<'_>, s2: &mut SlimStrMut<'_>) {
1631 let a: &SlimStrMut<'_> = s1;
1632 let b: &SlimStrMut<'_> = s2;
1633
1634 assert_eq!(a.deref(), TEST_STR);
1635 assert_eq!(SlimStrBox::from(a).clone().deref(), TEST_STR);
1636 assert_eq!(b.deref(), TEST_STR2);
1637
1638 assert_eq!(String::from(a), TEST_STR);
1639 assert_eq!(<Box<str>>::from(a).deref(), TEST_STR);
1640 assert_eq!(SlimStrBox::from(a).deref(), TEST_STR);
1641 assert_eq!(<Box<str>>::from(SlimStrBox::from(a)).deref(), TEST_STR);
1642
1643 general_properties(a, b, TEST_STR, TEST_STR2);
1644 display_properties(a, b, TEST_STR, TEST_STR2);
1645
1646 s1.deref_mut().make_ascii_uppercase();
1647 assert_eq!(&**s1, TEST_STR.to_uppercase());
1648 }
1649
1650 #[test]
1651 fn str_mut_call() {
1652 let [mut s1, mut s2] = test_strings();
1653 let s1 = &mut from_str_mut(s1.as_mut_str());
1654 let s2 = &mut from_str_mut(s2.as_mut_str());
1655 assert_str_mut_properties(s1, s2);
1656 }
1657
1658 #[test]
1659 fn str_mut_try_into() {
1660 let [mut s1, mut s2] = test_strings();
1661 let s1: &mut SlimStrMut = &mut s1.as_mut().try_into().unwrap();
1662 let s2: &mut SlimStrMut = &mut s2.as_mut().try_into().unwrap();
1663 assert_str_mut_properties(s1, s2);
1664 }
1665
1666 #[test]
1667 fn str_mut_exclusive_ref_various() {
1668 for [mut a, mut b] in various_boxed_strs() {
1669 assert_str_mut_properties(a.exclusive_ref(), b.exclusive_ref())
1670 }
1671 }
1672
1673 fn assert_str_properties(a: &SlimStr<'_>, b: &SlimStr<'_>) {
1674 assert_eq!(a.deref(), TEST_STR);
1675 assert_eq!(SlimStrBox::from(a).clone().deref(), TEST_STR);
1676 assert_eq!(b.deref(), TEST_STR2);
1677
1678 assert_eq!(String::from(a), TEST_STR);
1679 assert_eq!(<Box<str>>::from(a).deref(), TEST_STR);
1680 assert_eq!(SlimStrBox::from(a).deref(), TEST_STR);
1681 assert_eq!(String::from(SlimStrBox::from(a)).deref(), TEST_STR);
1682 assert_eq!(<Box<str>>::from(SlimStrBox::from(a)).deref(), TEST_STR);
1683
1684 general_properties(a, b, TEST_STR, TEST_STR2);
1685 display_properties(a, b, TEST_STR, TEST_STR2);
1686 }
1687
1688 #[test]
1689 fn str_call() {
1690 let [s1, s2] = test_strings();
1691 assert_str_properties(&from_str(&s1), &from_str(&s2));
1692 }
1693
1694 #[test]
1695 fn str_try_into() {
1696 let [s1, s2] = test_strings();
1697 let s1: &SlimStr = &mut s1.deref().try_into().unwrap();
1698 let s2: &SlimStr = &mut s2.deref().try_into().unwrap();
1699 assert_str_properties(s1, s2);
1700 }
1701
1702 #[test]
1703 fn str_shared_ref_various() {
1704 for [a, b] in various_boxed_strs() {
1705 assert_str_properties(a.shared_ref(), b.shared_ref())
1706 }
1707 }
1708
1709 fn assert_slice_mut_properties(s1: &mut SlimSliceMut<'_, u8>, s2: &mut SlimSliceMut<'_, u8>) {
1710 let a: &SlimSliceMut<'_, u8> = s1;
1711 let b: &SlimSliceMut<'_, u8> = s2;
1712
1713 assert_eq!(a.deref(), TEST_SLICE);
1714 assert_eq!(SlimSliceBox::from(a).clone().deref(), TEST_SLICE);
1715 assert_eq!(b.deref(), TEST_SLICE2);
1716
1717 assert_eq!(<Vec<u8>>::from(a), TEST_SLICE);
1718 assert_eq!(<Box<[u8]>>::from(a).deref(), TEST_SLICE);
1719 assert_eq!(<SlimSliceBox<u8>>::from(a).deref(), TEST_SLICE);
1720 assert_eq!(<Vec<u8>>::from(<SlimSliceBox<u8>>::from(a)).deref(), TEST_SLICE);
1721
1722 general_properties(a, b, TEST_SLICE, TEST_SLICE2);
1723
1724 s1.deref_mut().make_ascii_uppercase();
1725 let mut upper = TEST_SLICE.to_owned();
1726 upper.iter_mut().for_each(|x| x.make_ascii_uppercase());
1727 assert_eq!(&**s1, upper);
1728 }
1729
1730 #[test]
1731 fn slice_mut_call() {
1732 let [mut s1, mut s2] = test_slices();
1733 let s1 = &mut from_slice_mut(s1.as_mut());
1734 let s2 = &mut from_slice_mut(s2.as_mut());
1735 assert_slice_mut_properties(s1, s2);
1736 }
1737
1738 #[test]
1739 fn slice_mut_try_into() {
1740 let [mut s1, mut s2] = test_slices();
1741 let s1: &mut SlimSliceMut<u8> = &mut s1.deref_mut().try_into().unwrap();
1742 let s2: &mut SlimSliceMut<u8> = &mut s2.deref_mut().try_into().unwrap();
1743 assert_slice_mut_properties(s1, s2);
1744 }
1745
1746 #[test]
1747 fn slice_mut_exclusive_ref_various() {
1748 for [mut a, mut b] in various_boxed_slices() {
1749 assert_slice_mut_properties(a.exclusive_ref(), b.exclusive_ref());
1750 }
1751 }
1752
1753 fn assert_slice_properties(a: &SlimSlice<'_, u8>, b: &SlimSlice<'_, u8>) {
1754 assert_eq!(a.deref(), TEST_SLICE);
1755 assert_eq!(SlimSliceBox::from(a).clone().deref(), TEST_SLICE);
1756 assert_eq!(b.deref(), TEST_SLICE2);
1757
1758 assert_eq!(<Vec<u8>>::from(a), TEST_SLICE);
1759 assert_eq!(<Box<[u8]>>::from(a).deref(), TEST_SLICE);
1760 assert_eq!(<SlimSliceBox<u8>>::from(a).deref(), TEST_SLICE);
1761 assert_eq!(<Vec<u8>>::from(<SlimSliceBox<u8>>::from(a)).deref(), TEST_SLICE);
1762
1763 general_properties(a, b, TEST_SLICE, TEST_SLICE2);
1764 }
1765
1766 #[test]
1767 fn slice_call() {
1768 let [s1, s2] = test_slices();
1769 assert_slice_properties(&from_slice(&s1), &from_slice(&s2));
1770 }
1771
1772 #[test]
1773 fn slice_try_into() {
1774 let [s1, s2] = test_slices();
1775 let s1: &SlimSlice<u8> = &s1.deref().try_into().unwrap();
1776 let s2: &SlimSlice<u8> = &s2.deref().try_into().unwrap();
1777 assert_slice_properties(s1, s2);
1778 }
1779
1780 #[test]
1781 fn slice_shared_ref_various() {
1782 for [a, b] in various_boxed_slices() {
1783 assert_slice_properties(a.shared_ref(), b.shared_ref())
1784 }
1785 }
1786}