icrate 0.0.1

Bindings to Apple's frameworks
Documentation
#[cfg(feature = "block")]
use alloc::vec::Vec;
use core::ffi::c_void;
use core::ops::{Index, IndexMut, Range};
use core::ptr::NonNull;
use core::slice::{self, SliceIndex};
use std::io;

use objc2::rc::{DefaultId, Id, Owned, Shared};
use objc2::{extern_methods, ClassType};

use super::data::with_slice;
use crate::Foundation::{NSCopying, NSData, NSMutableCopying, NSMutableData, NSRange};

extern_methods!(
    /// Creation methods
    unsafe impl NSMutableData {
        #[method_id(new)]
        pub fn new() -> Id<Self, Owned>;

        pub fn with_bytes(bytes: &[u8]) -> Id<Self, Owned> {
            unsafe { Id::from_shared(Id::cast(with_slice(Self::class(), bytes))) }
        }

        #[cfg(feature = "block")]
        pub fn from_vec(bytes: Vec<u8>) -> Id<Self, Owned> {
            unsafe { Id::from_shared(Id::cast(super::data::with_vec(Self::class(), bytes))) }
        }
    }

    /// Mutation methods
    unsafe impl NSMutableData {
        #[doc(alias = "mutableBytes")]
        pub fn bytes_mut(&mut self) -> &mut [u8] {
            if let Some(ptr) = self.mutableBytes() {
                let ptr: *mut u8 = ptr.as_ptr().cast();
                unsafe { slice::from_raw_parts_mut(ptr, self.len()) }
            } else {
                // The bytes pointer may be null for length zero on GNUStep
                &mut []
            }
        }

        #[doc(alias = "appendBytes:length:")]
        pub fn extend_from_slice(&mut self, bytes: &[u8]) {
            let bytes_ptr: NonNull<c_void> =
                NonNull::new(bytes.as_ptr() as *mut u8).unwrap().cast();
            unsafe { self.appendBytes_length(bytes_ptr, bytes.len()) }
        }

        pub fn push(&mut self, byte: u8) {
            self.extend_from_slice(&[byte])
        }

        #[doc(alias = "replaceBytesInRange:withBytes:length:")]
        pub fn replace_range(&mut self, range: Range<usize>, bytes: &[u8]) {
            let range = NSRange::from(range);
            // No need to verify the length of the range here,
            // `replaceBytesInRange:` just zero-fills if out of bounds.
            let ptr = bytes.as_ptr() as *mut c_void;
            unsafe { self.replaceBytesInRange_withBytes_length(range, ptr, bytes.len()) }
        }

        pub fn set_bytes(&mut self, bytes: &[u8]) {
            let len = self.len();
            self.replace_range(0..len, bytes);
        }
    }
);

unsafe impl NSCopying for NSMutableData {
    type Ownership = Shared;
    type Output = NSData;
}

unsafe impl NSMutableCopying for NSMutableData {
    type Output = NSMutableData;
}

impl alloc::borrow::ToOwned for NSMutableData {
    type Owned = Id<NSMutableData, Owned>;
    fn to_owned(&self) -> Self::Owned {
        self.mutable_copy()
    }
}

impl AsRef<[u8]> for NSMutableData {
    fn as_ref(&self) -> &[u8] {
        self.bytes()
    }
}

impl AsMut<[u8]> for NSMutableData {
    fn as_mut(&mut self) -> &mut [u8] {
        self.bytes_mut()
    }
}

impl<I: SliceIndex<[u8]>> Index<I> for NSMutableData {
    type Output = I::Output;

    #[inline]
    fn index(&self, index: I) -> &Self::Output {
        Index::index(self.bytes(), index)
    }
}

impl<I: SliceIndex<[u8]>> IndexMut<I> for NSMutableData {
    #[inline]
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
        IndexMut::index_mut(self.bytes_mut(), index)
    }
}

// impl FromIterator<u8> for Id<NSMutableData, Owned> {
//     fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
//         let iter = iter.into_iter();
//         let (lower, _) = iter.size_hint();
//         let data = Self::with_capacity(lower);
//         for item in iter {
//             data.push(item);
//         }
//         data
//     }
// }

impl Extend<u8> for NSMutableData {
    /// You should use [`extend_from_slice`] whenever possible, it is more
    /// performant.
    ///
    /// [`extend_from_slice`]: Self::extend_from_slice
    fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
        let iterator = iter.into_iter();
        iterator.for_each(move |item| self.push(item));
    }
}

// Vec also has this impl
impl<'a> Extend<&'a u8> for NSMutableData {
    fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, iter: T) {
        let iterator = iter.into_iter();
        iterator.for_each(move |item| self.push(*item));
    }
}

impl io::Write for NSMutableData {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.extend_from_slice(buf);
        Ok(buf.len())
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.extend_from_slice(buf);
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl DefaultId for NSMutableData {
    type Ownership = Owned;

    #[inline]
    fn default_id() -> Id<Self, Self::Ownership> {
        Self::new()
    }
}

impl<'a> IntoIterator for &'a NSMutableData {
    type Item = &'a u8;
    type IntoIter = core::slice::Iter<'a, u8>;

    fn into_iter(self) -> Self::IntoIter {
        self.bytes().iter()
    }
}

impl<'a> IntoIterator for &'a mut NSMutableData {
    type Item = &'a mut u8;
    type IntoIter = core::slice::IterMut<'a, u8>;

    fn into_iter(self) -> Self::IntoIter {
        self.bytes_mut().iter_mut()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use objc2::runtime::Object;

    use crate::Foundation::NSObject;

    #[test]
    fn test_bytes_mut() {
        let mut data = NSMutableData::with_bytes(&[7, 16]);
        data.bytes_mut()[0] = 3;
        assert_eq!(data.bytes(), [3, 16]);
    }

    #[test]
    fn test_set_len() {
        let mut data = NSMutableData::with_bytes(&[7, 16]);
        data.setLength(4);
        assert_eq!(data.len(), 4);
        assert_eq!(data.bytes(), [7, 16, 0, 0]);

        data.setLength(1);
        assert_eq!(data.len(), 1);
        assert_eq!(data.bytes(), [7]);
    }

    #[test]
    fn test_append() {
        let mut data = NSMutableData::with_bytes(&[7, 16]);
        data.extend_from_slice(&[3, 52]);
        assert_eq!(data.len(), 4);
        assert_eq!(data.bytes(), [7, 16, 3, 52]);
    }

    #[test]
    fn test_replace() {
        let mut data = NSMutableData::with_bytes(&[7, 16]);
        data.replace_range(0..0, &[3]);
        assert_eq!(data.bytes(), [3, 7, 16]);

        data.replace_range(1..2, &[52, 13]);
        assert_eq!(data.bytes(), [3, 52, 13, 16]);

        data.replace_range(2..4, &[6]);
        assert_eq!(data.bytes(), [3, 52, 6]);

        data.set_bytes(&[8, 17]);
        assert_eq!(data.bytes(), [8, 17]);
    }

    #[test]
    fn test_from_data() {
        let data = NSData::with_bytes(&[1, 2]);
        let mut_data = NSMutableData::dataWithData(&data);
        assert_eq!(&*data, &**mut_data);
    }

    #[test]
    fn test_with_capacity() {
        let mut data = NSMutableData::dataWithCapacity(5).unwrap();
        assert_eq!(data.bytes(), &[]);
        data.extend_from_slice(&[1, 2, 3, 4, 5]);
        assert_eq!(data.bytes(), &[1, 2, 3, 4, 5]);
        data.extend_from_slice(&[6, 7]);
        assert_eq!(data.bytes(), &[1, 2, 3, 4, 5, 6, 7]);
    }

    #[test]
    fn test_extend() {
        let mut data = NSMutableData::with_bytes(&[1, 2]);
        data.extend(3..=5);
        assert_eq!(data.bytes(), &[1, 2, 3, 4, 5]);
        data.extend(&*NSData::with_bytes(&[6, 7]));
        assert_eq!(data.bytes(), &[1, 2, 3, 4, 5, 6, 7]);
    }

    #[test]
    fn test_as_ref_borrow() {
        use core::borrow::{Borrow, BorrowMut};

        fn impls_borrow<T: AsRef<U> + Borrow<U> + ?Sized, U: ?Sized>(_: &T) {}
        fn impls_borrow_mut<T: AsMut<U> + BorrowMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}

        let mut obj = NSMutableData::new();
        impls_borrow::<Id<NSMutableData, Owned>, NSMutableData>(&obj);
        impls_borrow_mut::<Id<NSMutableData, Owned>, NSMutableData>(&mut obj);

        impls_borrow::<NSMutableData, NSMutableData>(&obj);
        impls_borrow_mut::<NSMutableData, NSMutableData>(&mut obj);
        impls_borrow::<NSMutableData, NSData>(&obj);
        impls_borrow_mut::<NSMutableData, NSData>(&mut obj);
        impls_borrow::<NSMutableData, NSObject>(&obj);
        impls_borrow_mut::<NSMutableData, NSObject>(&mut obj);
        impls_borrow::<NSMutableData, Object>(&obj);
        impls_borrow_mut::<NSMutableData, Object>(&mut obj);

        impls_borrow::<NSData, NSData>(&obj);
        impls_borrow_mut::<NSData, NSData>(&mut obj);
        impls_borrow::<NSData, NSObject>(&obj);
        impls_borrow_mut::<NSData, NSObject>(&mut obj);
        impls_borrow::<NSData, Object>(&obj);
        impls_borrow_mut::<NSData, Object>(&mut obj);

        fn impls_as_ref<T: AsRef<U> + ?Sized, U: ?Sized>(_: &T) {}
        fn impls_as_mut<T: AsMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}

        impls_as_ref::<NSMutableData, [u8]>(&obj);
        impls_as_mut::<NSMutableData, [u8]>(&mut obj);
        impls_as_ref::<NSData, [u8]>(&obj);

        let obj: &mut NSMutableData = &mut obj;
        let _: &[u8] = obj.as_ref();
        let _: &mut [u8] = obj.as_mut();

        let obj: &mut NSData = obj;
        let _: &[u8] = obj.as_ref();
    }
}