objc2_foundation/
data.rs

1use alloc::vec::Vec;
2use core::ffi::c_void;
3use core::fmt;
4use core::marker::PhantomData;
5#[cfg(feature = "NSRange")]
6use core::ops::Range;
7use core::panic::{RefUnwindSafe, UnwindSafe};
8use core::ptr::NonNull;
9use core::slice::{self};
10
11use objc2::rc::Retained;
12#[cfg(feature = "block2")]
13use objc2::rc::RetainedFromIterator;
14use objc2::{extern_methods, AnyThread};
15
16use crate::{NSData, NSMutableData};
17
18impl UnwindSafe for NSData {}
19impl RefUnwindSafe for NSData {}
20
21// GNUStep returns NULL from these methods, and Apple's documentation says
22// that's valid (even though the headers say otherwise).
23impl NSData {
24    extern_methods!(
25        #[unsafe(method(bytes))]
26        pub(crate) fn bytes_raw(&self) -> *const c_void;
27    );
28}
29
30impl NSMutableData {
31    extern_methods!(
32        #[unsafe(method(mutableBytes))]
33        pub(crate) fn mutable_bytes_raw(&self) -> *mut c_void;
34    );
35}
36
37impl NSData {
38    // TODO: Rename to `from_bytes` to match `CFData::from_bytes`.
39    pub fn with_bytes(bytes: &[u8]) -> Retained<Self> {
40        let bytes_ptr = bytes.as_ptr() as *mut c_void;
41        unsafe { Self::initWithBytes_length(Self::alloc(), bytes_ptr, bytes.len()) }
42    }
43
44    #[cfg(feature = "block2")]
45    #[cfg(feature = "alloc")]
46    pub fn from_vec(bytes: Vec<u8>) -> Retained<Self> {
47        unsafe { with_vec(Self::alloc(), bytes) }
48    }
49}
50
51impl NSMutableData {
52    pub fn with_bytes(bytes: &[u8]) -> Retained<Self> {
53        let bytes_ptr = bytes.as_ptr() as *mut c_void;
54        // SAFETY: Same as `NSData::with_bytes`
55        unsafe { Self::initWithBytes_length(Self::alloc(), bytes_ptr, bytes.len()) }
56    }
57
58    #[cfg(feature = "block2")]
59    pub fn from_vec(bytes: Vec<u8>) -> Retained<Self> {
60        // SAFETY: Same as `NSData::from_vec`
61        unsafe { with_vec(Self::alloc(), bytes) }
62    }
63}
64
65impl NSData {
66    pub fn len(&self) -> usize {
67        self.length()
68    }
69
70    pub fn is_empty(&self) -> bool {
71        self.len() == 0
72    }
73
74    /// The bytes in the data.
75    ///
76    /// # Safety
77    ///
78    /// The data must not be mutated while the returned slice is alive.
79    /// Consider using [`to_vec`] instead if this requirement is a bit
80    /// difficult to uphold.
81    ///
82    /// [`to_vec`]: Self::to_vec
83    pub unsafe fn as_bytes_unchecked(&self) -> &[u8] {
84        let ptr = self.bytes_raw();
85        if !ptr.is_null() {
86            let ptr: *const u8 = ptr.cast();
87            // SAFETY: The pointer is checked to not be NULL, and since we're
88            // working with raw bytes (`u8`), the alignment is also correct.
89            //
90            // The pointer is guaranteed to be valid for as long as the data
91            // is alive, or until it is mutated, see the documentation:
92            // <https://developer.apple.com/documentation/foundation/nsdata/1410616-bytes?language=objc>
93            //
94            // By bounding the lifetime of the returned slice to `self`, we
95            // ensure that the data is not deallocated while the slice is
96            // alive.
97            //
98            // Caller ensures that the data is not mutated for the lifetime of
99            // the slice.
100            unsafe { slice::from_raw_parts(ptr, self.len()) }
101        } else {
102            // The bytes pointer may be null for length zero
103            &[]
104        }
105    }
106
107    /// Copy the contents of the data into a new [`Vec`].
108    pub fn to_vec(&self) -> Vec<u8> {
109        // NOTE: We don't do `Vec::from`, as that will call the allocator
110        // while the buffer is active, and we don't know if that allocator
111        // uses a CFMutableData under the hood (though very theoretical).
112
113        let mut vec = Vec::with_capacity(self.len());
114        // SAFETY: We've pre-allocated the Vec, so it won't call the allocator
115        // while the byte slice is alive (and hence it won't ).
116        vec.extend_from_slice(unsafe { self.as_bytes_unchecked() });
117        vec
118    }
119
120    /// Iterate over the bytes of the data.
121    pub fn iter(&self) -> Iter<'_> {
122        Iter::new(self)
123    }
124}
125
126impl NSMutableData {
127    /// A mutable view of the bytes in the data.
128    ///
129    /// # Safety
130    ///
131    /// No methods on the `NSMutableData` may be called while the returned
132    /// slice is alive.
133    #[doc(alias = "mutableBytes")]
134    #[allow(clippy::mut_from_ref)]
135    pub unsafe fn as_mut_bytes_unchecked(&self) -> &mut [u8] {
136        let ptr = self.mutable_bytes_raw();
137        // &Cell<[u8]> is safe because the slice length is not actually in the
138        // cell
139        if !ptr.is_null() {
140            let ptr: *mut u8 = ptr.cast();
141            // SAFETY: Same as `NSData::bytes`, with the addition that a
142            // mutable slice is safe, as the caller upholds that the slice is
143            // not .
144            unsafe { slice::from_raw_parts_mut(ptr, self.len()) }
145        } else {
146            &mut []
147        }
148    }
149
150    #[doc(alias = "appendBytes:length:")]
151    pub fn extend_from_slice(&self, bytes: &[u8]) {
152        let bytes_ptr: NonNull<c_void> = NonNull::new(bytes.as_ptr() as *mut u8).unwrap().cast();
153        unsafe { self.appendBytes_length(bytes_ptr, bytes.len()) }
154    }
155
156    pub fn push(&self, byte: u8) {
157        self.extend_from_slice(&[byte]);
158    }
159
160    #[doc(alias = "replaceBytesInRange:withBytes:length:")]
161    #[cfg(feature = "NSRange")]
162    pub fn replace_range(&self, range: Range<usize>, bytes: &[u8]) {
163        // No need to verify the length of the range here,
164        // `replaceBytesInRange:` zero-fills if out of bounds.
165        let ptr = bytes.as_ptr().cast();
166        unsafe { self.replaceBytesInRange_withBytes_length(range.into(), ptr, bytes.len()) }
167    }
168
169    #[cfg(feature = "NSRange")]
170    pub fn set_bytes(&self, bytes: &[u8]) {
171        let len = self.len();
172        self.replace_range(0..len, bytes);
173    }
174}
175
176impl fmt::Debug for NSData {
177    #[inline]
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        // -[NSData description] is quite unreadable
180        f.debug_list().entries(self.iter()).finish()
181    }
182}
183
184/// An iterator over the bytes in an `NSData`.
185///
186///
187/// # Panics
188///
189/// The iteration may panic if the data is mutated while being iterated upon.
190//
191// TODO: The implementation of this currently copies the `NSData` and iterates
192// using `Vec`. We should consider optimizing this by using a stack buffer
193// that we continuously copy into using `CFDataGetBytes`, or perhaps by getting
194// the pointer from `bytes` (or `CFDataGetBytePtr`) and copying directly from
195// that.
196#[derive(Debug, Clone)]
197pub struct Iter<'a> {
198    p: PhantomData<&'a NSData>,
199    #[cfg(debug_assertions)]
200    data: &'a NSData,
201    #[cfg(debug_assertions)]
202    length: usize,
203    bytes: alloc::vec::IntoIter<u8>,
204}
205
206impl<'a> Iter<'a> {
207    fn new(data: &'a NSData) -> Self {
208        Self {
209            p: PhantomData,
210            #[cfg(debug_assertions)]
211            data,
212            #[cfg(debug_assertions)]
213            length: data.length(),
214            bytes: data.to_vec().into_iter(),
215        }
216    }
217}
218
219impl ExactSizeIterator for Iter<'_> {
220    fn len(&self) -> usize {
221        self.bytes.len()
222    }
223}
224
225impl Iterator for Iter<'_> {
226    type Item = u8;
227
228    fn next(&mut self) -> Option<Self::Item> {
229        #[cfg(debug_assertions)]
230        {
231            if self.length != self.data.length() {
232                panic!("NSData was mutated while iterating");
233            }
234        }
235
236        self.bytes.next()
237    }
238
239    fn size_hint(&self) -> (usize, Option<usize>) {
240        let len = self.len();
241        (len, Some(len))
242    }
243}
244
245// TODO: Consider this after the final implementation
246// impl DoubleEndedIterator for Iter<'_> {
247//     fn next_back(&mut self) -> Option<Self::Item> {
248//         self.bytes.next_back()
249//     }
250// }
251
252impl core::iter::FusedIterator for Iter<'_> {}
253
254impl<'a> IntoIterator for &'a NSData {
255    type Item = u8;
256    type IntoIter = Iter<'a>;
257
258    fn into_iter(self) -> Self::IntoIter {
259        Iter::new(self)
260    }
261}
262
263impl<'a> IntoIterator for &'a NSMutableData {
264    type Item = u8;
265    type IntoIter = Iter<'a>;
266
267    fn into_iter(self) -> Self::IntoIter {
268        Iter::new(self)
269    }
270}
271
272impl Extend<u8> for &NSMutableData {
273    /// You should use [`extend_from_slice`] whenever possible, it is more
274    /// performant.
275    ///
276    /// [`extend_from_slice`]: NSMutableData::extend_from_slice
277    fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
278        let iterator = iter.into_iter();
279        iterator.for_each(move |item| self.push(item));
280    }
281}
282
283// Vec also has this impl
284impl<'a> Extend<&'a u8> for &NSMutableData {
285    fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, iter: T) {
286        let iterator = iter.into_iter();
287        iterator.for_each(move |item| self.push(*item));
288    }
289}
290
291#[cfg(feature = "std")]
292impl std::io::Write for &NSMutableData {
293    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
294        self.extend_from_slice(buf);
295        Ok(buf.len())
296    }
297
298    fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
299        self.extend_from_slice(buf);
300        Ok(())
301    }
302
303    fn flush(&mut self) -> std::io::Result<()> {
304        Ok(())
305    }
306}
307
308#[cfg(feature = "block2")]
309impl RetainedFromIterator<u8> for NSData {
310    fn retained_from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Retained<Self> {
311        let vec = Vec::from_iter(iter);
312        Self::from_vec(vec)
313    }
314}
315
316#[cfg(feature = "block2")]
317impl RetainedFromIterator<u8> for NSMutableData {
318    fn retained_from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Retained<Self> {
319        let vec = Vec::from_iter(iter);
320        Self::from_vec(vec)
321    }
322}
323
324#[cfg(feature = "block2")]
325#[cfg(feature = "alloc")]
326unsafe fn with_vec<T: objc2::Message>(obj: objc2::rc::Allocated<T>, bytes: Vec<u8>) -> Retained<T> {
327    use core::mem::ManuallyDrop;
328
329    use block2::{DynBlock, RcBlock};
330
331    let capacity = bytes.capacity();
332
333    let dealloc = RcBlock::new(move |bytes: *mut c_void, len: usize| {
334        // Recreate the Vec and let it drop
335        let _ = unsafe { <Vec<u8>>::from_raw_parts(bytes.cast(), len, capacity) };
336    });
337    let dealloc: &DynBlock<dyn Fn(*mut c_void, usize) + 'static> = &dealloc;
338
339    let mut bytes = ManuallyDrop::new(bytes);
340    // We intentionally extract the length before we access the
341    // pointer as mutable, to not invalidate that mutable pointer.
342    let len = bytes.len();
343    let bytes_ptr: *mut c_void = bytes.as_mut_ptr().cast();
344
345    unsafe {
346        objc2::msg_send![
347            obj,
348            initWithBytesNoCopy: bytes_ptr,
349            length: len,
350            deallocator: dealloc,
351        ]
352    }
353}