diff options
Diffstat (limited to 'vendor/windows-core/src/array.rs')
| -rw-r--r-- | vendor/windows-core/src/array.rs | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/vendor/windows-core/src/array.rs b/vendor/windows-core/src/array.rs new file mode 100644 index 00000000..1dca64f1 --- /dev/null +++ b/vendor/windows-core/src/array.rs @@ -0,0 +1,186 @@ +use super::*; + +/// A WinRT array stores elements contiguously in a heap-allocated buffer. +pub struct Array<T: Type<T>> { + data: *mut T::Default, + len: u32, +} + +impl<T: Type<T>> Default for Array<T> { + fn default() -> Self { + Array { + data: core::ptr::null_mut(), + len: 0, + } + } +} + +impl<T: Type<T>> Array<T> { + /// Creates an empty array. + pub fn new() -> Self { + Self::default() + } + + /// Creates an array of the given length with default values. + pub fn with_len(len: usize) -> Self { + assert!(len < u32::MAX as usize); + let bytes_amount = len + .checked_mul(core::mem::size_of::<T>()) + .expect("Attempted to allocate too large an Array"); + + // WinRT arrays must be allocated with CoTaskMemAlloc. + // SAFETY: the call to CoTaskMemAlloc is safe to perform + // if len is zero and overflow was checked above. + // We ensured we alloc enough space by multiplying len * size_of::<T> + let data = unsafe { imp::CoTaskMemAlloc(bytes_amount) as *mut T::Default }; + + assert!(!data.is_null(), "Could not successfully allocate for Array"); + + // SAFETY: It is by definition safe to zero-initialize WinRT types. + // `write_bytes` will write 0 to (len * size_of::<T>()) + // bytes making the entire array zero initialized. We have assured + // above that the data ptr is not null. + unsafe { + core::ptr::write_bytes(data, 0, len); + } + + let len = len as u32; + Self { data, len } + } + + /// Creates an array by copying the elements from the slice. + pub fn from_slice(values: &[T::Default]) -> Self + where + T::Default: Clone, + { + let mut array = Self::with_len(values.len()); + array.clone_from_slice(values); + array + } + + /// Creates an array from a pointer and length. The `len` argument is the number of elements, not the number of bytes. + /// # Safety + /// The `data` argument must have been allocated with `CoTaskMemAlloc`. + pub unsafe fn from_raw_parts(data: *mut T::Default, len: u32) -> Self { + Self { data, len } + } + + /// Returns a slice containing the entire array. + pub fn as_slice(&self) -> &[T::Default] { + self + } + + /// Returns `true` if the array is empty. + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Returns the length of the array. + pub fn len(&self) -> usize { + self.len as usize + } + + /// Clears the contents of the array. + pub fn clear(&mut self) { + if self.is_empty() { + return; + } + + let mut data = core::ptr::null_mut(); + let mut len = 0; + + core::mem::swap(&mut data, &mut self.data); + core::mem::swap(&mut len, &mut self.len); + + // SAFETY: At this point, self has been reset to zero so any panics in T's destructor would + // only leak data not leave the array in bad state. + unsafe { + // Call the destructors of all the elements of the old array + // SAFETY: the slice cannot be used after the call to `drop_in_place` + core::ptr::drop_in_place(core::slice::from_raw_parts_mut(data, len as usize)); + // Free the data memory where the elements were + // SAFETY: we have unique access to the data pointer at this point + // so freeing it is the right thing to do + imp::CoTaskMemFree(data as _); + } + } + + #[doc(hidden)] + /// Get a mutable pointer to the array's length + /// + /// # Safety + /// + /// This function is safe but writing to the pointer is not. Calling this without + /// a subsequent call to `set_abi` is likely to either leak memory or cause UB + pub unsafe fn set_abi_len(&mut self) -> *mut u32 { + &mut self.len + } + + #[doc(hidden)] + /// Turn the array into a pointer to its data and its length + pub fn into_abi(self) -> (*mut T::Abi, u32) { + let abi = (self.data as *mut _, self.len); + core::mem::forget(self); + abi + } +} + +impl<T: Type<T>> core::ops::Deref for Array<T> { + type Target = [T::Default]; + + fn deref(&self) -> &[T::Default] { + if self.is_empty() { + return &[]; + } + + // SAFETY: data must not be null if the array is not empty + unsafe { core::slice::from_raw_parts(self.data, self.len as usize) } + } +} + +impl<T: Type<T>> core::ops::DerefMut for Array<T> { + fn deref_mut(&mut self) -> &mut [T::Default] { + if self.is_empty() { + return &mut []; + } + + // SAFETY: data must not be null if the array is not empty + unsafe { core::slice::from_raw_parts_mut(self.data, self.len as usize) } + } +} + +impl<T: Type<T>> Drop for Array<T> { + fn drop(&mut self) { + self.clear(); + } +} + +#[doc(hidden)] +pub struct ArrayProxy<T: Type<T>> { + data: *mut *mut T::Default, + len: *mut u32, + temp: core::mem::ManuallyDrop<Array<T>>, +} + +impl<T: Type<T>> ArrayProxy<T> { + pub fn from_raw_parts(data: *mut *mut T::Default, len: *mut u32) -> Self { + Self { + data, + len, + temp: core::mem::ManuallyDrop::new(Array::new()), + } + } + + pub fn as_array(&mut self) -> &mut Array<T> { + &mut self.temp + } +} + +impl<T: Type<T>> Drop for ArrayProxy<T> { + fn drop(&mut self) { + unsafe { + *self.data = self.temp.data; + *self.len = self.temp.len; + } + } +} |
