dst_container/
smart_ptr.rs1use crate::*;
2use std::{
3 alloc::{handle_alloc_error, AllocError, Allocator, Global, Layout},
4 ptr::NonNull,
5 rc::Rc,
6 sync::Arc,
7};
8
9pub trait SmartPtr: Sized {
11 type Content: ?Sized;
13
14 type Rebind<U: ?Sized>: SmartPtr<Content = U>;
16
17 unsafe fn from_alloc(p: *mut Self::Content) -> Self;
21
22 unsafe fn rebind<U>(self) -> Self::Rebind<U>
26 where
27 U: Pointee<Metadata = <Self::Content as Pointee>::Metadata> + ?Sized;
28}
29
30impl<T: ?Sized> SmartPtr for Box<T> {
31 type Content = T;
32
33 type Rebind<U: ?Sized> = Box<U>;
34
35 unsafe fn from_alloc(p: *mut Self::Content) -> Self {
36 Self::from_raw(p)
37 }
38
39 unsafe fn rebind<U>(self) -> Self::Rebind<U>
40 where
41 U: Pointee<Metadata = <Self::Content as Pointee>::Metadata> + ?Sized,
42 {
43 let (ptr, metadata) = Box::into_raw(self).to_raw_parts();
44 Box::from_raw(std::ptr::from_raw_parts_mut(ptr, metadata))
45 }
46}
47
48impl<T: ?Sized> SmartPtr for Rc<T> {
49 type Content = T;
50
51 type Rebind<U: ?Sized> = Rc<U>;
52
53 unsafe fn from_alloc(p: *mut Self::Content) -> Self {
54 Box::from_alloc(p).into()
55 }
56
57 unsafe fn rebind<U>(self) -> Self::Rebind<U>
58 where
59 U: Pointee<Metadata = <Self::Content as Pointee>::Metadata> + ?Sized,
60 {
61 let (ptr, metadata) = Rc::into_raw(self).to_raw_parts();
62 Rc::from_raw(std::ptr::from_raw_parts(ptr, metadata))
63 }
64}
65
66impl<T: ?Sized> SmartPtr for Arc<T> {
67 type Content = T;
68
69 type Rebind<U: ?Sized> = Arc<U>;
70
71 unsafe fn from_alloc(p: *mut Self::Content) -> Self {
72 Box::from_alloc(p).into()
73 }
74
75 unsafe fn rebind<U>(self) -> Self::Rebind<U>
76 where
77 U: Pointee<Metadata = <Self::Content as Pointee>::Metadata> + ?Sized,
78 {
79 let (ptr, metadata) = Arc::into_raw(self).to_raw_parts();
80 Arc::from_raw(std::ptr::from_raw_parts(ptr, metadata))
81 }
82}
83
84type RebindPtr<P, U> = <P as SmartPtr>::Rebind<U>;
85
86mod sealed {
87 pub trait Sealed {}
88}
89
90use sealed::Sealed;
91impl<P: SmartPtr> Sealed for P {}
92
93pub trait NewUninit: Sealed + SmartPtr
95where
96 Self::Content: MaybeUninitProject,
97{
98 fn new_uninit_unsized(
100 metadata: <Self::Content as Pointee>::Metadata,
101 ) -> RebindPtr<Self, <Self::Content as MaybeUninitProject>::Target> {
102 unsafe {
103 RebindPtr::<Self, <Self::Content as MaybeUninitProject>::Target>::from_alloc(
104 alloc_with_metadata::<Self::Content>(metadata),
105 )
106 }
107 }
108
109 fn new_zeroed_unsized(
111 metadata: <Self::Content as Pointee>::Metadata,
112 ) -> RebindPtr<Self, <Self::Content as MaybeUninitProject>::Target> {
113 unsafe {
114 RebindPtr::<Self, <Self::Content as MaybeUninitProject>::Target>::from_alloc(
115 zeroed_with_metadata::<Self::Content>(metadata),
116 )
117 }
118 }
119
120 unsafe fn new_unsized_with(
124 metadata: <Self::Content as Pointee>::Metadata,
125 f: impl FnOnce(&mut <Self::Content as MaybeUninitProject>::Target),
126 ) -> Self
127 where
129 Self::Rebind<<Self::Content as MaybeUninitProject>::Target>:
130 SmartPtr<Rebind<Self::Content> = Self>,
131 {
132 let ptr = alloc_with_metadata::<Self::Content>(metadata);
133 f(&mut *ptr);
134 RebindPtr::<Self, <Self::Content as MaybeUninitProject>::Target>::from_alloc(ptr)
135 .rebind::<Self::Content>()
136 }
137}
138
139impl<P: SmartPtr> NewUninit for P where P::Content: MaybeUninitProject {}
140
141unsafe fn alloc_with_metadata_impl<T: ?Sized + MaybeUninitProject>(
142 metadata: <T as Pointee>::Metadata,
143 alloc: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
144) -> *mut T::Target {
145 let null_ptr: *mut T = std::ptr::from_raw_parts_mut(std::ptr::null_mut::<()>(), metadata);
146 let layout = Layout::for_value_raw(null_ptr);
147 if let Ok(ptr) = alloc(layout) {
148 std::ptr::from_raw_parts_mut(ptr.as_mut_ptr() as *mut (), metadata)
149 } else {
150 handle_alloc_error(layout)
151 }
152}
153
154unsafe fn alloc_with_metadata<T: ?Sized + MaybeUninitProject>(
155 metadata: <T as Pointee>::Metadata,
156) -> *mut T::Target {
157 alloc_with_metadata_impl::<T>(metadata, |layout| Global.allocate(layout))
158}
159
160unsafe fn zeroed_with_metadata<T: ?Sized + MaybeUninitProject>(
161 metadata: <T as Pointee>::Metadata,
162) -> *mut T::Target {
163 alloc_with_metadata_impl::<T>(metadata, |layout| Global.allocate_zeroed(layout))
164}
165
166pub trait AssumeInit<T: ?Sized + MaybeUninitProject>:
168 Sealed + SmartPtr<Content = T::Target>
169{
170 unsafe fn assume_init(self) -> RebindPtr<Self, T> {
174 self.rebind()
175 }
176}
177
178impl<T: ?Sized + MaybeUninitProject, P: SmartPtr<Content = T::Target>> AssumeInit<T> for P {}
179
180#[cfg(test)]
181mod test {
182 use crate::*;
183 use std::{rc::Rc, sync::Arc};
184
185 #[test]
186 fn sized() {
187 let s: Box<u32> = unsafe { Box::<u32>::new_zeroed_unsized(()).assume_init() };
188 assert_eq!(s.as_ref(), &0);
189 }
190
191 #[derive(MaybeUninitProject)]
192 #[repr(transparent)]
193 struct SliceWrapper([u8]);
194
195 #[test]
196 fn slice_wrapper() {
197 let s: Box<SliceWrapper> =
198 unsafe { Box::<SliceWrapper>::new_zeroed_unsized(64).assume_init() };
199 assert_eq!(&s.0, &[0u8; 64]);
200
201 let s: Rc<SliceWrapper> =
202 unsafe { Rc::<SliceWrapper>::new_zeroed_unsized(64).assume_init() };
203 assert_eq!(&s.0, &[0u8; 64]);
204
205 let s: Arc<SliceWrapper> =
206 unsafe { Arc::<SliceWrapper>::new_zeroed_unsized(64).assume_init() };
207 assert_eq!(&s.0, &[0u8; 64]);
208 }
209}
210
211#[cfg(test)]
212mod bench {
213 use crate::*;
214 use test::{black_box, Bencher};
215
216 const SLICE_LEN: usize = 10000;
217
218 #[bench]
219 fn dst_uninit(b: &mut Bencher) {
220 b.iter(|| unsafe {
221 let b: Box<UnsizedSlice<(), u32>> =
222 Box::<UnsizedSlice<(), u32>>::new_uninit_unsized(SLICE_LEN).assume_init();
223 black_box(b)
224 })
225 }
226
227 #[bench]
228 fn dst_uninit_write(b: &mut Bencher) {
229 b.iter(|| unsafe {
230 let b = Box::<UnsizedSlice<(), u32>>::new_unsized_with(SLICE_LEN, |slice| {
231 slice.slice.write_copy_of_slice(&[0; SLICE_LEN]);
232 });
233 black_box(b)
234 })
235 }
236
237 #[bench]
238 fn dst_zeroed(b: &mut Bencher) {
239 b.iter(|| unsafe {
240 let b: Box<UnsizedSlice<(), u32>> =
241 Box::<UnsizedSlice<(), u32>>::new_zeroed_unsized(SLICE_LEN).assume_init();
242 black_box(b)
243 })
244 }
245
246 #[bench]
247 fn box_from(b: &mut Bencher) {
248 b.iter(|| unsafe {
249 let b: Box<[u32]> = Box::new_zeroed_slice(SLICE_LEN).assume_init();
250 black_box(b)
251 })
252 }
253
254 #[bench]
255 fn vec_into(b: &mut Bencher) {
256 b.iter(|| {
257 let b = vec![0u32; SLICE_LEN].into_boxed_slice();
258 black_box(b)
259 })
260 }
261}