use alloc::vec::Vec;
use core::ffi::c_void;
use core::fmt;
use core::marker::PhantomData;
#[cfg(feature = "NSRange")]
use core::ops::Range;
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::ptr::NonNull;
use core::slice::{self};
use objc2::rc::Retained;
#[cfg(feature = "block2")]
use objc2::rc::RetainedFromIterator;
use objc2::{extern_methods, AllocAnyThread};
use crate::{NSData, NSMutableData};
impl UnwindSafe for NSData {}
impl RefUnwindSafe for NSData {}
impl NSData {
extern_methods!(
#[unsafe(method(bytes))]
pub(crate) fn bytes_raw(&self) -> *const c_void;
);
}
impl NSMutableData {
extern_methods!(
#[unsafe(method(mutableBytes))]
pub(crate) fn mutable_bytes_raw(&self) -> *mut c_void;
);
}
impl NSData {
pub fn with_bytes(bytes: &[u8]) -> Retained<Self> {
let bytes_ptr = bytes.as_ptr() as *mut c_void;
unsafe { Self::initWithBytes_length(Self::alloc(), bytes_ptr, bytes.len()) }
}
#[cfg(feature = "block2")]
#[cfg(feature = "alloc")]
pub fn from_vec(bytes: Vec<u8>) -> Retained<Self> {
unsafe { with_vec(Self::alloc(), bytes) }
}
}
impl NSMutableData {
pub fn with_bytes(bytes: &[u8]) -> Retained<Self> {
let bytes_ptr = bytes.as_ptr() as *mut c_void;
unsafe { Self::initWithBytes_length(Self::alloc(), bytes_ptr, bytes.len()) }
}
#[cfg(feature = "block2")]
pub fn from_vec(bytes: Vec<u8>) -> Retained<Self> {
unsafe { with_vec(Self::alloc(), bytes) }
}
}
impl NSData {
pub fn len(&self) -> usize {
self.length()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub unsafe fn as_bytes_unchecked(&self) -> &[u8] {
let ptr = self.bytes_raw();
if !ptr.is_null() {
let ptr: *const u8 = ptr.cast();
unsafe { slice::from_raw_parts(ptr, self.len()) }
} else {
&[]
}
}
pub fn to_vec(&self) -> Vec<u8> {
let mut vec = Vec::with_capacity(self.len());
vec.extend_from_slice(unsafe { self.as_bytes_unchecked() });
vec
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(self)
}
}
impl NSMutableData {
#[doc(alias = "mutableBytes")]
#[allow(clippy::mut_from_ref)]
pub unsafe fn as_mut_bytes_unchecked(&self) -> &mut [u8] {
let ptr = self.mutable_bytes_raw();
if !ptr.is_null() {
let ptr: *mut u8 = ptr.cast();
unsafe { slice::from_raw_parts_mut(ptr, self.len()) }
} else {
&mut []
}
}
#[doc(alias = "appendBytes:length:")]
pub fn extend_from_slice(&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(&self, byte: u8) {
self.extend_from_slice(&[byte]);
}
#[doc(alias = "replaceBytesInRange:withBytes:length:")]
#[cfg(feature = "NSRange")]
pub fn replace_range(&self, range: Range<usize>, bytes: &[u8]) {
let ptr = bytes.as_ptr().cast();
unsafe { self.replaceBytesInRange_withBytes_length(range.into(), ptr, bytes.len()) }
}
#[cfg(feature = "NSRange")]
pub fn set_bytes(&self, bytes: &[u8]) {
let len = self.len();
self.replace_range(0..len, bytes);
}
}
impl fmt::Debug for NSData {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
#[derive(Debug, Clone)]
pub struct Iter<'a> {
p: PhantomData<&'a NSData>,
#[cfg(debug_assertions)]
data: &'a NSData,
#[cfg(debug_assertions)]
length: usize,
bytes: alloc::vec::IntoIter<u8>,
}
impl<'a> Iter<'a> {
fn new(data: &'a NSData) -> Self {
Self {
p: PhantomData,
#[cfg(debug_assertions)]
data,
#[cfg(debug_assertions)]
length: data.length(),
bytes: data.to_vec().into_iter(),
}
}
}
impl ExactSizeIterator for Iter<'_> {
fn len(&self) -> usize {
self.bytes.len()
}
}
impl Iterator for Iter<'_> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
#[cfg(debug_assertions)]
{
if self.length != self.data.length() {
panic!("NSData was mutated while iterating");
}
}
self.bytes.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl core::iter::FusedIterator for Iter<'_> {}
impl<'a> IntoIterator for &'a NSData {
type Item = u8;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
impl<'a> IntoIterator for &'a NSMutableData {
type Item = u8;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
impl Extend<u8> for &NSMutableData {
fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
let iterator = iter.into_iter();
iterator.for_each(move |item| self.push(item));
}
}
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));
}
}
#[cfg(feature = "std")]
impl std::io::Write for &NSMutableData {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.extend_from_slice(buf);
Ok(buf.len())
}
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
self.extend_from_slice(buf);
Ok(())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[cfg(feature = "block2")]
impl RetainedFromIterator<u8> for NSData {
fn retained_from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Retained<Self> {
let vec = Vec::from_iter(iter);
Self::from_vec(vec)
}
}
#[cfg(feature = "block2")]
impl RetainedFromIterator<u8> for NSMutableData {
fn retained_from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Retained<Self> {
let vec = Vec::from_iter(iter);
Self::from_vec(vec)
}
}
#[cfg(feature = "block2")]
#[cfg(feature = "alloc")]
unsafe fn with_vec<T: objc2::Message>(obj: objc2::rc::Allocated<T>, bytes: Vec<u8>) -> Retained<T> {
use core::mem::ManuallyDrop;
use block2::{Block, RcBlock};
let capacity = bytes.capacity();
let dealloc = RcBlock::new(move |bytes: *mut c_void, len: usize| {
let _ = unsafe { <Vec<u8>>::from_raw_parts(bytes.cast(), len, capacity) };
});
let dealloc: &Block<dyn Fn(*mut c_void, usize) + 'static> = &dealloc;
let mut bytes = ManuallyDrop::new(bytes);
let len = bytes.len();
let bytes_ptr: *mut c_void = bytes.as_mut_ptr().cast();
unsafe {
objc2::msg_send![
obj,
initWithBytesNoCopy: bytes_ptr,
length: len,
deallocator: dealloc,
]
}
}