|
1 | 1 | //! Dispatch object definition.
|
2 | 2 |
|
3 | 3 | use alloc::boxed::Box;
|
| 4 | +use core::{ops::Deref, ptr::NonNull}; |
4 | 5 |
|
5 | 6 | use super::{ffi::*, queue::Queue, utils::function_wrapper, QualityOfServiceClass};
|
6 | 7 |
|
| 8 | +// TODO: Autogenerate with https://github.com/madsmtm/objc2/issues/609 |
| 9 | +const DISPATCH_DATA_DESTRUCTOR_DEFAULT: dispatch_block_t = std::ptr::null_mut(); |
| 10 | + |
7 | 11 | /// Error returned by [DispatchObject::set_target_queue].
|
8 | 12 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
9 | 13 | #[non_exhaustive]
|
@@ -60,6 +64,77 @@ impl<T> DispatchObject<T> {
|
60 | 64 | result
|
61 | 65 | }
|
62 | 66 |
|
| 67 | + /// Creates a dispatch data object with a copy of the given contiguous buffer of memory. |
| 68 | + // TODO: Would it be safe for users to replace the finalizer? |
| 69 | + pub fn data_create_copy(data: &[u8], queue: &Queue) -> Self { |
| 70 | + // SAFETY: Buffer pointer is valid for the given number of bytes. Queue handle is valid, |
| 71 | + // and the destructor is a NULL value which indicates the buffer should be copied. |
| 72 | + let object = unsafe { |
| 73 | + dispatch_data_create( |
| 74 | + NonNull::new_unchecked(data.as_ptr().cast_mut()).cast(), |
| 75 | + data.len(), |
| 76 | + queue.as_raw(), |
| 77 | + DISPATCH_DATA_DESTRUCTOR_DEFAULT, |
| 78 | + ) |
| 79 | + }; |
| 80 | + |
| 81 | + Self { |
| 82 | + object: object.cast(), |
| 83 | + is_activated: false, |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + /// Creates a dispatch data object with a reference to the given contiguous buffer of memory. |
| 88 | + pub fn data_create_static(data: &'static [u8], queue: &Queue) -> Self { |
| 89 | + block2::global_block! { |
| 90 | + static NOOP_BLOCK = || {} |
| 91 | + } |
| 92 | + // SAFETY: Buffer pointer is valid for the given number of bytes. Queue handle is valid, |
| 93 | + // and the destructor is a NULL value which indicates the buffer should be copied. |
| 94 | + let object = unsafe { |
| 95 | + dispatch_data_create( |
| 96 | + NonNull::new_unchecked(data.as_ptr().cast_mut()).cast(), |
| 97 | + data.len(), |
| 98 | + queue.as_raw(), |
| 99 | + <*const _>::cast_mut(NOOP_BLOCK.deref()), |
| 100 | + ) |
| 101 | + }; |
| 102 | + |
| 103 | + Self { |
| 104 | + object: object.cast(), |
| 105 | + is_activated: false, |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + /// Creates a dispatch data object with ownership of the given contiguous buffer of memory. |
| 110 | + // TODO: Would it be safe for users to replace the finalizer? |
| 111 | + pub fn data_create(data: Box<[u8]>, queue: &Queue) -> Self { |
| 112 | + let data_len = data.len(); |
| 113 | + let raw = Box::into_raw(data); |
| 114 | + let delete_box = block2::RcBlock::new(move || { |
| 115 | + // SAFETY: The fat pointer (plus size) was retrieved from Box::into_raw(), and its |
| 116 | + // ownership was *not* consumed by dispatch_data_create(). |
| 117 | + let _ = unsafe { Box::<[u8]>::from_raw(raw) }; |
| 118 | + }); |
| 119 | + |
| 120 | + // SAFETY: Buffer pointer is valid for the given number of bytes. Queue handle is valid, |
| 121 | + // and the destructor is a NULL value which indicates the buffer should be copied. |
| 122 | + // let t = Box::into_raw(data); |
| 123 | + let object = unsafe { |
| 124 | + dispatch_data_create( |
| 125 | + NonNull::new_unchecked(raw).cast(), |
| 126 | + data_len, |
| 127 | + queue.as_raw(), |
| 128 | + <*const _>::cast_mut(delete_box.deref()), |
| 129 | + ) |
| 130 | + }; |
| 131 | + |
| 132 | + Self { |
| 133 | + object: object.cast(), |
| 134 | + is_activated: false, |
| 135 | + } |
| 136 | + } |
| 137 | + |
63 | 138 | /// Set the finalizer function for the object.
|
64 | 139 | pub fn set_finalizer<F>(&mut self, destructor: F)
|
65 | 140 | where
|
|
0 commit comments