1#![cfg_attr(not(test), no_std)]
38
39use core::borrow::Borrow;
40use core::cmp::max;
41use core::hash::{Hash, Hasher};
42use core::marker::PhantomData;
43use core::mem::{align_of, size_of};
44use core::ops::{Deref, DerefMut};
45use core::ptr::NonNull;
46use core::slice;
47
48use allocator_api2::alloc::{self, Allocator, Global};
49
50mod tests;
51
52#[derive(Debug)]
53pub struct ThinBoxedSlice<T, A: Allocator = Global> {
54 p: NonNull<u8>,
55 allocator: A,
56 phantom: PhantomData<T>,
57}
58
59impl<T, A: Allocator> ThinBoxedSlice<T, A> {
60 const fn array_offset() -> usize {
61 let align = align_of::<T>();
62 let misalign = size_of::<usize>() % align;
63 let padding = if misalign == 0 { 0 } else { align - misalign };
64 size_of::<usize>() + padding
65 }
66 fn layout(n: usize) -> alloc::Layout {
67 let alloc_len = Self::array_offset() + n * size_of::<T>();
68 let align = max(align_of::<usize>(), align_of::<T>());
69 alloc::Layout::from_size_align(alloc_len, align).unwrap()
70 }
71 fn array_ptr(&self) -> *mut T {
72 unsafe { self.p.clone().as_ptr().add(Self::array_offset()) as *mut T }
73 }
74 fn len(&self) -> usize {
75 unsafe { self.p.cast::<usize>().clone().as_ptr().read() }
77 }
78}
79
80impl<T: Clone, A: Allocator> ThinBoxedSlice<T, A> {
81 pub fn new_in(s: &[T], allocator: A) -> Self {
82 let layout = Self::layout(s.len());
83 unsafe {
84 let p = allocator.allocate(layout).unwrap().cast::<u8>();
85 let ret = Self {
86 p: p.clone(),
87 allocator,
88 phantom: PhantomData::default(),
89 };
90 p.cast::<usize>().as_ptr().write(s.len());
92 let mut v = ret.array_ptr();
93 for i in 0..s.len() {
95 v.write(s[i].clone());
96 v = v.add(1);
97 }
98 ret
99 }
100 }
101}
102
103impl<T, A: Allocator> Drop for ThinBoxedSlice<T, A> {
104 fn drop(&mut self) {
105 unsafe {
106 self.allocator.deallocate(self.p, Self::layout(self.len()));
107 }
108 }
109}
110
111impl<T: Clone, A: Allocator + Default> From<&[T]> for ThinBoxedSlice<T, A> {
112 fn from(value: &[T]) -> Self {
113 Self::new_in(value, A::default())
114 }
115}
116
117impl<T: Clone, A: Allocator + Default, const N: usize> From<&[T; N]>
118 for ThinBoxedSlice<T, A>
119{
120 fn from(value: &[T; N]) -> Self {
121 Self::from(value.as_slice())
122 }
123}
124
125impl<T, A: Allocator> Deref for ThinBoxedSlice<T, A> {
126 type Target = [T];
127 fn deref(&self) -> &Self::Target {
128 unsafe { slice::from_raw_parts(self.array_ptr(), self.len()) }
129 }
130}
131
132impl<T, A: Allocator> DerefMut for ThinBoxedSlice<T, A> {
133 fn deref_mut(&mut self) -> &mut Self::Target {
134 unsafe { slice::from_raw_parts_mut(self.array_ptr(), self.len()) }
135 }
136}
137
138impl<T, A: Allocator> Borrow<[T]> for ThinBoxedSlice<T, A> {
139 fn borrow(&self) -> &[T] {
140 self.deref()
141 }
142}
143
144impl<T: PartialEq, A: Allocator> PartialEq for ThinBoxedSlice<T, A> {
145 fn eq(&self, other: &Self) -> bool {
146 self.deref() == other.deref()
147 }
148}
149
150impl<T: PartialEq, A: Allocator> Eq for ThinBoxedSlice<T, A> {
151 fn assert_receiver_is_total_eq(&self) {}
152}
153
154impl<T: Hash, A: Allocator> Hash for ThinBoxedSlice<T, A> {
155 fn hash<H: Hasher>(&self, state: &mut H) {
156 self.deref().hash(state);
157 }
158}