1 use std::mem;
2 use std::ops::Range;
3 use std::os::raw::c_void;
4 use std::slice;
5 
6 use objc_id::Id;
7 use block::{Block, ConcreteBlock};
8 use {INSObject, INSCopying, INSMutableCopying, NSRange};
9 
10 pub trait INSData : INSObject {
11     fn len(&self) -> usize {
12         unsafe {
13             msg_send![self, length]
14         }
15     }
16 
17     fn bytes(&self) -> &[u8] {
18         let ptr: *const c_void = unsafe { msg_send![self, bytes] };
19         // The bytes pointer may be null for length zero
20         let (ptr, len) = if ptr.is_null() {
21             (0x1 as *const u8, 0)
22         } else {
23             (ptr as *const u8, self.len())
24         };
25         unsafe {
26             slice::from_raw_parts(ptr, len)
27         }
28     }
29 
30     fn with_bytes(bytes: &[u8]) -> Id<Self> {
31         let cls = Self::class();
32         unsafe {
33             let obj: *mut Self = msg_send![cls, alloc];
34             let obj: *mut Self = msg_send![obj, initWithBytes:bytes.as_ptr()
35                                                        length:bytes.len()];
36             Id::from_retained_ptr(obj)
37         }
38     }
39 
40     fn from_vec(bytes: Vec<u8>) -> Id<Self> {
41         let capacity = bytes.capacity();
42         let dealloc = ConcreteBlock::new(move |bytes: *mut c_void, len: usize| unsafe {
43             // Recreate the Vec and let it drop
44             let _ = Vec::from_raw_parts(bytes as *mut u8, len, capacity);
45         });
46         let dealloc = dealloc.copy();
47         let dealloc: &Block<(*mut c_void, usize), ()> = &dealloc;
48 
49         let mut bytes = bytes;
50         let cls = Self::class();
51         unsafe {
52             let obj: *mut Self = msg_send![cls, alloc];
53             let obj: *mut Self = msg_send![obj, initWithBytesNoCopy:bytes.as_mut_ptr()
54                                                              length:bytes.len()
55                                                         deallocator:dealloc];
56             mem::forget(bytes);
57             Id::from_retained_ptr(obj)
58         }
59     }
60 }
61 
62 object_struct!(NSData);
63 
64 impl INSData for NSData { }
65 
66 impl INSCopying for NSData {
67     type Output = NSData;
68 }
69 
70 impl INSMutableCopying for NSData {
71     type Output = NSMutableData;
72 }
73 
74 pub trait INSMutableData : INSData {
75     fn bytes_mut(&mut self) -> &mut [u8] {
76         let ptr: *mut c_void = unsafe { msg_send![self, mutableBytes] };
77         // The bytes pointer may be null for length zero
78         let (ptr, len) = if ptr.is_null() {
79             (0x1 as *mut u8, 0)
80         } else {
81             (ptr as *mut u8, self.len())
82         };
83         unsafe {
84             slice::from_raw_parts_mut(ptr, len)
85         }
86     }
87 
88     fn set_len(&mut self, len: usize) {
89         unsafe {
90             let _: () = msg_send![self, setLength:len];
91         }
92     }
93 
94     fn append(&mut self, bytes: &[u8]) {
95         unsafe {
96             let _: () = msg_send![self, appendBytes:bytes.as_ptr()
97                                              length:bytes.len()];
98         }
99     }
100 
101     fn replace_range(&mut self, range: Range<usize>, bytes: &[u8]) {
102         let range = NSRange::from_range(range);
103         unsafe {
104             let _: () = msg_send![self, replaceBytesInRange:range
105                                                   withBytes:bytes.as_ptr()
106                                                      length:bytes.len()];
107         }
108     }
109 
110     fn set_bytes(&mut self, bytes: &[u8]) {
111         let len = self.len();
112         self.replace_range(0..len, bytes);
113     }
114 }
115 
116 object_struct!(NSMutableData);
117 
118 impl INSData for NSMutableData { }
119 
120 impl INSMutableData for NSMutableData { }
121 
122 impl INSCopying for NSMutableData {
123     type Output = NSData;
124 }
125 
126 impl INSMutableCopying for NSMutableData {
127     type Output = NSMutableData;
128 }
129 
130 #[cfg(test)]
131 mod tests {
132     use INSObject;
133     use super::{INSData, INSMutableData, NSData, NSMutableData};
134 
135     #[test]
136     fn test_bytes() {
137         let bytes = [3, 7, 16, 52, 112, 19];
138         let data = NSData::with_bytes(&bytes);
139         assert!(data.len() == bytes.len());
140         assert!(data.bytes() == bytes);
141     }
142 
143     #[test]
144     fn test_no_bytes() {
145         let data = NSData::new();
146         assert!(Some(data.bytes()).is_some());
147     }
148 
149     #[test]
150     fn test_bytes_mut() {
151         let mut data = NSMutableData::with_bytes(&[7, 16]);
152         data.bytes_mut()[0] = 3;
153         assert!(data.bytes() == [3, 16]);
154     }
155 
156     #[test]
157     fn test_set_len() {
158         let mut data = NSMutableData::with_bytes(&[7, 16]);
159         data.set_len(4);
160         assert!(data.len() == 4);
161         assert!(data.bytes() == [7, 16, 0, 0]);
162 
163         data.set_len(1);
164         assert!(data.len() == 1);
165         assert!(data.bytes() == [7]);
166     }
167 
168     #[test]
169     fn test_append() {
170         let mut data = NSMutableData::with_bytes(&[7, 16]);
171         data.append(&[3, 52]);
172         assert!(data.len() == 4);
173         assert!(data.bytes() == [7, 16, 3, 52]);
174     }
175 
176     #[test]
177     fn test_replace() {
178         let mut data = NSMutableData::with_bytes(&[7, 16]);
179         data.replace_range(0..0, &[3]);
180         assert!(data.bytes() == [3, 7, 16]);
181 
182         data.replace_range(1..2, &[52, 13]);
183         assert!(data.bytes() == [3, 52, 13, 16]);
184 
185         data.replace_range(2..4, &[6]);
186         assert!(data.bytes() == [3, 52, 6]);
187 
188         data.set_bytes(&[8, 17]);
189         assert!(data.bytes() == [8, 17]);
190     }
191 
192     #[test]
193     fn test_from_vec() {
194         let bytes = vec![3, 7, 16];
195         let bytes_ptr = bytes.as_ptr();
196 
197         let data = NSData::from_vec(bytes);
198         assert!(data.bytes().as_ptr() == bytes_ptr);
199     }
200 }
201