1use super::{AllocErr, OwnedAlloc, RawVec};
2use std::{
3 alloc::{alloc, dealloc, handle_alloc_error, Layout},
4 fmt,
5 marker::PhantomData,
6 mem,
7 ptr::NonNull,
8};
9
10pub struct UninitAlloc<T>
16where
17 T: ?Sized,
18{
19 nnptr: NonNull<T>,
20 _marker: PhantomData<T>,
21}
22
23impl<T> UninitAlloc<T> {
24 pub fn new() -> Self {
27 Self::try_new().unwrap_or_else(|err| handle_alloc_error(err.layout))
28 }
29
30 pub fn try_new() -> Result<Self, AllocErr> {
32 let layout = Layout::new::<T>();
33
34 let res = if layout.size() == 0 {
35 Ok(NonNull::dangling())
36 } else {
37 NonNull::new(unsafe { alloc(layout) })
38 .map(NonNull::cast::<T>)
39 .ok_or(AllocErr { layout })
40 };
41
42 res.map(|nnptr| Self { nnptr, _marker: PhantomData })
43 }
44
45 pub fn init(self, val: T) -> OwnedAlloc<T> {
48 let raw = self.into_raw();
49 unsafe {
50 raw.as_ptr().write(val);
51 OwnedAlloc::from_raw(raw)
52 }
53 }
54}
55
56impl<T> UninitAlloc<T>
57where
58 T: ?Sized,
59{
60 pub unsafe fn init_in_place<F>(self, init: F) -> OwnedAlloc<T>
68 where
69 F: FnOnce(&mut T),
70 {
71 let mut raw = self.into_raw();
72 init(raw.as_mut());
73 OwnedAlloc::from_raw(raw)
74 }
75
76 pub unsafe fn from_raw(nnptr: NonNull<T>) -> Self {
82 Self { nnptr, _marker: PhantomData }
83 }
84
85 pub fn raw(&self) -> NonNull<T> {
87 self.nnptr
88 }
89
90 pub fn into_raw(self) -> NonNull<T> {
92 let nnptr = self.nnptr;
93 mem::forget(self);
94 nnptr
95 }
96}
97
98impl<T> Drop for UninitAlloc<T>
99where
100 T: ?Sized,
101{
102 fn drop(&mut self) {
103 unsafe {
104 let layout = Layout::for_value(self.nnptr.as_ref());
105
106 if layout.size() != 0 {
107 dealloc(self.nnptr.cast().as_ptr(), layout);
108 }
109 }
110 }
111}
112
113impl<T> fmt::Debug for UninitAlloc<T>
114where
115 T: ?Sized,
116{
117 fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
118 write!(fmtr, "{:?}", self.nnptr)
119 }
120}
121
122impl<T> From<RawVec<T>> for UninitAlloc<[T]> {
123 fn from(alloc: RawVec<T>) -> Self {
124 Self { nnptr: alloc.into_raw_slice(), _marker: PhantomData }
125 }
126}
127
128unsafe impl<T> Send for UninitAlloc<T> where T: ?Sized + Send {}
129unsafe impl<T> Sync for UninitAlloc<T> where T: ?Sized + Sync {}
130
131#[cfg(test)]
132mod test {
133 use super::UninitAlloc;
134
135 #[test]
136 fn into_from_raw() {
137 let alloc = UninitAlloc::<usize>::new();
138 let raw_borrowed = alloc.raw();
139 let raw = alloc.into_raw();
140
141 assert_eq!(raw, raw_borrowed);
142
143 let alloc = unsafe { UninitAlloc::from_raw(raw) };
144 assert_eq!(alloc.raw(), raw_borrowed);
145 }
146}