1 | use super::*; |
2 | |
3 | /// A WinRT array stores elements contiguously in a heap-allocated buffer. |
4 | pub struct Array<T: Type<T>> { |
5 | data: *mut T::Default, |
6 | len: u32, |
7 | } |
8 | |
9 | impl<T: Type<T>> Default for Array<T> { |
10 | fn default() -> Self { |
11 | Array { data: std::ptr::null_mut(), len: 0 } |
12 | } |
13 | } |
14 | |
15 | impl<T: Type<T>> Array<T> { |
16 | /// Creates an empty array. |
17 | pub fn new() -> Self { |
18 | Self::default() |
19 | } |
20 | |
21 | /// Creates an array of the given length with default values. |
22 | pub fn with_len(len: usize) -> Self { |
23 | assert!(len < std::u32::MAX as usize); |
24 | let bytes_amount = len.checked_mul(std::mem::size_of::<T>()).expect("Attempted to allocate too large an Array" ); |
25 | |
26 | // WinRT arrays must be allocated with CoTaskMemAlloc. |
27 | // SAFETY: the call to CoTaskMemAlloc is safe to perform |
28 | // if len is zero and overflow was checked above. |
29 | // We ensured we alloc enough space by multiplying len * size_of::<T> |
30 | let data = unsafe { crate::imp::CoTaskMemAlloc(bytes_amount) as *mut T::Default }; |
31 | |
32 | assert!(!data.is_null(), "Could not successfully allocate for Array" ); |
33 | |
34 | // SAFETY: It is by definition safe to zero-initialize WinRT types. |
35 | // `write_bytes` will write 0 to (len * size_of::<T>()) |
36 | // bytes making the entire array zero initialized. We have assured |
37 | // above that the data ptr is not null. |
38 | unsafe { |
39 | std::ptr::write_bytes(data, 0, len); |
40 | } |
41 | |
42 | let len = len as u32; |
43 | Self { data, len } |
44 | } |
45 | |
46 | /// Creates an array by copying the elements from the slice. |
47 | pub fn from_slice(values: &[T::Default]) -> Self |
48 | where |
49 | T::Default: Clone, |
50 | { |
51 | let mut array = Self::with_len(values.len()); |
52 | array.clone_from_slice(values); |
53 | array |
54 | } |
55 | |
56 | /// Creates an array from a pointer and length. The `len` argument is the number of elements, not the number of bytes. |
57 | /// # Safety |
58 | /// The `data` argument must have been allocated with `CoTaskMemAlloc`. |
59 | pub unsafe fn from_raw_parts(data: *mut T::Default, len: u32) -> Self { |
60 | Self { data, len } |
61 | } |
62 | |
63 | /// Returns a slice containing the entire array. |
64 | pub fn as_slice(&self) -> &[T::Default] { |
65 | self |
66 | } |
67 | |
68 | /// Returns `true` if the array is empty. |
69 | pub fn is_empty(&self) -> bool { |
70 | self.len == 0 |
71 | } |
72 | |
73 | /// Returns the length of the array. |
74 | pub fn len(&self) -> usize { |
75 | self.len as usize |
76 | } |
77 | |
78 | /// Clears the contents of the array. |
79 | pub fn clear(&mut self) { |
80 | if self.is_empty() { |
81 | return; |
82 | } |
83 | |
84 | let mut data = std::ptr::null_mut(); |
85 | let mut len = 0; |
86 | |
87 | std::mem::swap(&mut data, &mut self.data); |
88 | std::mem::swap(&mut len, &mut self.len); |
89 | |
90 | // SAFETY: At this point, self has been reset to zero so any panics in T's destructor would |
91 | // only leak data not leave the array in bad state. |
92 | unsafe { |
93 | // Call the destructors of all the elements of the old array |
94 | // SAFETY: the slice cannot be used after the call to `drop_in_place` |
95 | std::ptr::drop_in_place(std::slice::from_raw_parts_mut(data, len as usize)); |
96 | // Free the data memory where the elements were |
97 | // SAFETY: we have unique access to the data pointer at this point |
98 | // so freeing it is the right thing to do |
99 | crate::imp::CoTaskMemFree(data as _); |
100 | } |
101 | } |
102 | |
103 | #[doc (hidden)] |
104 | /// Get a mutable pointer to the array's length |
105 | /// |
106 | /// # Safety |
107 | /// |
108 | /// This function is safe but writing to the pointer is not. Calling this without |
109 | /// a subsequent call to `set_abi` is likely to either leak memory or cause UB |
110 | pub unsafe fn set_abi_len(&mut self) -> *mut u32 { |
111 | &mut self.len |
112 | } |
113 | |
114 | #[doc (hidden)] |
115 | /// Turn the array into a pointer to its data and its length |
116 | pub fn into_abi(self) -> (*mut T::Abi, u32) { |
117 | let abi = (self.data as *mut _, self.len); |
118 | std::mem::forget(self); |
119 | abi |
120 | } |
121 | } |
122 | |
123 | impl<T: Type<T>> std::ops::Deref for Array<T> { |
124 | type Target = [T::Default]; |
125 | |
126 | fn deref(&self) -> &[T::Default] { |
127 | if self.is_empty() { |
128 | return &[]; |
129 | } |
130 | |
131 | // SAFETY: data must not be null if the array is not empty |
132 | unsafe { std::slice::from_raw_parts(self.data, self.len as usize) } |
133 | } |
134 | } |
135 | |
136 | impl<T: Type<T>> std::ops::DerefMut for Array<T> { |
137 | fn deref_mut(&mut self) -> &mut [T::Default] { |
138 | if self.is_empty() { |
139 | return &mut []; |
140 | } |
141 | |
142 | // SAFETY: data must not be null if the array is not empty |
143 | unsafe { std::slice::from_raw_parts_mut(self.data, self.len as usize) } |
144 | } |
145 | } |
146 | |
147 | impl<T: Type<T>> Drop for Array<T> { |
148 | fn drop(&mut self) { |
149 | self.clear(); |
150 | } |
151 | } |
152 | |
153 | #[doc (hidden)] |
154 | pub struct ArrayProxy<T: Type<T>> { |
155 | data: *mut *mut T::Default, |
156 | len: *mut u32, |
157 | temp: std::mem::ManuallyDrop<Array<T>>, |
158 | } |
159 | |
160 | impl<T: Type<T>> ArrayProxy<T> { |
161 | pub fn from_raw_parts(data: *mut *mut T::Default, len: *mut u32) -> Self { |
162 | Self { data, len, temp: std::mem::ManuallyDrop::new(Array::new()) } |
163 | } |
164 | |
165 | pub fn as_array(&mut self) -> &mut Array<T> { |
166 | &mut self.temp |
167 | } |
168 | } |
169 | |
170 | impl<T: Type<T>> Drop for ArrayProxy<T> { |
171 | fn drop(&mut self) { |
172 | unsafe { |
173 | *self.data = self.temp.data; |
174 | *self.len = self.temp.len; |
175 | } |
176 | } |
177 | } |
178 | |