use std::mem;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;
use std::slice;
use block::{Block, ConcreteBlock};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use crate::foundation::{id, to_bool, NSUInteger, BOOL, NO, YES};
#[derive(Debug)]
pub struct NSData(pub Id<Object>);
impl NSData {
pub fn new(bytes: Vec<u8>) -> Self {
let capacity = bytes.capacity();
let dealloc = ConcreteBlock::new(move |bytes: *mut c_void, len: usize| unsafe {
let _ = Vec::from_raw_parts(bytes as *mut u8, len, capacity);
});
let dealloc = dealloc.copy();
let dealloc: &Block<(*mut c_void, usize), ()> = &dealloc;
let mut bytes = bytes;
let bytes_ptr = bytes.as_mut_ptr() as *mut c_void;
unsafe {
let obj: id = msg_send![class!(NSData), alloc];
let obj: id = msg_send![obj, initWithBytesNoCopy:bytes_ptr
length:bytes.len()
deallocator:dealloc];
mem::forget(bytes);
NSData(Id::from_ptr(obj))
}
}
pub fn with_slice(bytes: &[u8]) -> Self {
let bytes_ptr = bytes.as_ptr() as *mut c_void;
unsafe {
let obj: id = msg_send![class!(NSData), dataWithBytes:bytes_ptr length:bytes.len()];
NSData(Id::from_ptr(obj))
}
}
pub fn retain(data: id) -> Self {
NSData(unsafe { Id::from_ptr(data) })
}
pub fn from_retained(data: id) -> Self {
NSData(unsafe { Id::from_retained_ptr(data) })
}
pub fn is(obj: id) -> bool {
let result: BOOL = unsafe { msg_send![obj, isKindOfClass: class!(NSData)] };
to_bool(result)
}
pub fn len(&self) -> usize {
unsafe {
let x: NSUInteger = msg_send![&*self.0, length];
x as usize
}
}
pub fn bytes(&self) -> &[u8] {
let ptr: *const c_void = unsafe { msg_send![&*self.0, bytes] };
let (ptr, len) = if ptr.is_null() {
(0x1 as *const u8, 0)
} else {
(ptr as *const u8, self.len())
};
unsafe { slice::from_raw_parts(ptr, len) }
}
pub fn into_vec(self) -> Vec<u8> {
let mut data = Vec::new();
let bytes = self.bytes();
data.resize(bytes.len(), 0);
data.copy_from_slice(bytes);
data
}
}
impl From<NSData> for id {
fn from(mut data: NSData) -> Self {
&mut *data.0
}
}
impl Deref for NSData {
type Target = Object;
fn deref(&self) -> &Object {
&*self.0
}
}
impl DerefMut for NSData {
fn deref_mut(&mut self) -> &mut Object {
&mut *self.0
}
}