heap_slice/
slice.rs

1use core::borrow::{Borrow, BorrowMut};
2use core::ops::{Deref, DerefMut};
3use core::hash::{Hash, Hasher};
4use core::marker::PhantomData;
5use core::cmp::Ordering;
6use core::{slice, fmt};
7use core::ptr::NonNull;
8
9/// Basically [`Box<[T]>`](alloc::boxed::Box), but smaller.
10pub struct HeapSlice<T>(NonNull<u8>, PhantomData<T>);
11
12unsafe impl<T: Send> Send for HeapSlice<T> {}
13unsafe impl<T: Sync> Sync for HeapSlice<T> {}
14
15impl<T: Clone> From<&[T]> for HeapSlice<T> {
16    fn from(value: &[T]) -> Self {
17        if value.is_empty() {
18            return Self::default();
19        }
20
21        let align = align_of::<usize>().max(align_of::<T>());
22        let size = align + size_of_val(value);
23        unsafe {
24            let ptr = alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, align).unwrap_unchecked());
25            (ptr as *mut usize).write(value.len());
26            let mut p = ptr.add(align) as *mut T;
27            for v in value {
28                p.write(v.clone());
29                p = p.add(1);
30            }
31            Self(NonNull::new_unchecked(ptr), PhantomData)
32        }
33    }
34}
35
36impl<T> Default for HeapSlice<T> {
37    fn default() -> Self {
38        Self(unsafe { NonNull::new_unchecked(sptr::invalid_mut(1)) }, PhantomData)
39    }
40}
41
42impl<T> Deref for HeapSlice<T> {
43    type Target = [T];
44    fn deref(&self) -> &Self::Target {
45        if self.0.as_ptr() as usize != 1 {
46            let align = align_of::<usize>().max(align_of::<T>());
47            unsafe { slice::from_raw_parts(self.0.as_ptr().add(align) as *const T, (self.0.as_ptr() as *const usize).read()) }
48        } else {
49            &[]
50        }
51    }
52}
53
54impl<T> DerefMut for HeapSlice<T> {
55    fn deref_mut(&mut self) -> &mut Self::Target {
56        if self.0.as_ptr() as usize != 1 {
57            let align = align_of::<usize>().max(align_of::<T>());
58            unsafe { slice::from_raw_parts_mut(self.0.as_ptr().add(align) as *mut T, (self.0.as_ptr() as *const usize).read()) }
59        } else {
60            &mut []
61        }
62    }
63}
64
65impl<T> Drop for HeapSlice<T> {
66    fn drop(&mut self) {
67        if self.0.as_ptr() as usize != 1 {
68            let values = &mut **self;
69            let align = align_of::<usize>().max(align_of::<T>());
70            let size = align + size_of_val(values);
71
72            unsafe {
73                for value in values.iter_mut() {
74                    (value as *mut T).drop_in_place();
75                }
76                alloc::alloc::dealloc(self.0.as_ptr(), alloc::alloc::Layout::from_size_align(size, align).unwrap_unchecked());
77            }
78        }
79    }
80}
81
82impl<T> AsRef<[T]> for HeapSlice<T> {
83    fn as_ref(&self) -> &[T] {
84        self
85    }
86}
87
88impl<T> AsMut<[T]> for HeapSlice<T> {
89    fn as_mut(&mut self) -> &mut [T] {
90        self
91    }
92}
93
94impl<T> Borrow<[T]> for HeapSlice<T> {
95    fn borrow(&self) -> &[T] {
96        self
97    }
98}
99
100impl<T> BorrowMut<[T]> for HeapSlice<T> {
101    fn borrow_mut(&mut self) -> &mut [T] {
102        self
103    }
104}
105
106impl<T: Hash> Hash for HeapSlice<T> {
107    fn hash<H: Hasher>(&self, state: &mut H) {
108        (**self).hash(state)
109    }
110}
111
112impl<T: fmt::Debug> fmt::Debug for HeapSlice<T> {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        write!(f, "{:?}", &**self)
115    }
116}
117
118impl<T: Clone> Clone for HeapSlice<T> {
119    fn clone(&self) -> Self {
120        Self::from(&**self)
121    }
122}
123
124impl<T: PartialEq, U: AsRef<[T]>> PartialEq<U> for HeapSlice<T> {
125    fn eq(&self, other: &U) -> bool {
126        (**self).eq(other.as_ref())
127    }
128}
129
130impl<T: Eq> Eq for HeapSlice<T> {}
131
132impl<T: PartialOrd, U: AsRef<[T]>> PartialOrd<U> for HeapSlice<T> {
133    fn partial_cmp(&self, other: &U) -> Option<Ordering> {
134        (**self).partial_cmp(other.as_ref())
135    }
136}
137
138impl<T: Ord> Ord for HeapSlice<T> {
139    fn cmp(&self, other: &Self) -> Ordering {
140        (**self).cmp(&**other)
141    }
142}
143
144#[test]
145fn test_basic() {
146    extern crate std;
147    use alloc::string::String;
148
149    assert_eq!(size_of::<HeapSlice<u8>>(), size_of::<usize>());
150    assert_eq!(size_of::<Option<HeapSlice<u8>>>(), size_of::<usize>());
151
152    macro_rules! assert_implements {
153        ($t:ty : $($tt:tt)*) => {{
154            fn f<T: $($tt)*>() {}
155            f::<$t>();
156        }};
157    }
158
159    assert_implements!(HeapSlice<u8>: Send + Sync + fmt::Debug + Clone + PartialEq + Eq + PartialOrd + Ord + Deref<Target = [u8]> + DerefMut + AsRef<[u8]> + AsMut<[u8]> + Borrow<[u8]> + BorrowMut<[u8]> + Hash + Default);
160
161    for content in [b"".as_slice(), b"h", b"he", b"hel", b"help", b"help me obi-wan kenobi, you're my only hope"] {
162        let mut v = HeapSlice::from(content);
163        assert_eq!(v, content);
164        assert_eq!(v.deref(), content);
165        assert_eq!(v.deref_mut(), content);
166        assert_eq!(v.as_ref(), content);
167        assert_eq!(v.as_mut(), content);
168        assert_eq!(<HeapSlice<u8> as Borrow<[u8]>>::borrow(&v), content);
169        assert_eq!(<HeapSlice<u8> as BorrowMut<[u8]>>::borrow_mut(&mut v), content);
170        if v.is_empty() {
171            assert_eq!(v.0.as_ptr() as usize, 1);
172        } else {
173            assert_ne!(v.0.as_ptr() as usize, 1);
174            assert_eq!((v.0.as_ptr() as usize) % align_of::<usize>(), 0);
175        }
176        std::thread::spawn(move || {
177            assert_eq!(v, content);
178            assert_eq!(v.deref(), content);
179            assert_eq!(v.deref_mut(), content);
180            assert_eq!(v.as_ref(), content);
181            assert_eq!(v.as_mut(), content);
182            assert_eq!(<HeapSlice<u8> as Borrow<[u8]>>::borrow(&v), content);
183            assert_eq!(<HeapSlice<u8> as BorrowMut<[u8]>>::borrow_mut(&mut v), content);
184            if v.is_empty() {
185                assert_eq!(v.0.as_ptr() as usize, 1);
186            } else {
187                assert_ne!(v.0.as_ptr() as usize, 1);
188                assert_eq!((v.0.as_ptr() as usize) % align_of::<usize>(), 0);
189            }
190        }).join().unwrap();
191    }
192
193    let vv = HeapSlice::<u8>::default();
194    assert_eq!(vv, &[]);
195    assert_eq!(vv.0.as_ptr() as usize, 1);
196
197    let x = HeapSlice::<String>::from([String::from("hello"), String::from("world")].as_slice());
198    assert_eq!(x.len(), 2);
199    assert_eq!(x[0], "hello");
200    assert_eq!(x[1], "world");
201
202    let xx = HeapSlice::<String>::default();
203    assert_eq!(xx, &[]);
204
205    let zz = HeapSlice::<u128>::from([1, 6, 3].as_slice());
206    assert_eq!(zz.len(), 3);
207    assert_eq!(zz[0], 1);
208    assert_eq!(zz[1], 6);
209    assert_eq!(zz[2], 3);
210}