Skip to content

Commit 08f7e6d

Browse files
committed
Improve NSMutableData
1 parent 063d612 commit 08f7e6d

File tree

1 file changed

+56
-40
lines changed

1 file changed

+56
-40
lines changed

objc2_foundation/src/data.rs

+56-40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#[cfg(feature = "block")]
22
use alloc::vec::Vec;
3-
use core::ops::Range;
3+
use core::ops::{Deref, DerefMut, Range};
44
use core::slice;
55
use core::{ffi::c_void, ptr::NonNull};
66

@@ -43,19 +43,19 @@ pub unsafe trait INSData: INSObject {
4343

4444
#[cfg(feature = "block")]
4545
fn from_vec(bytes: Vec<u8>) -> Id<Self, Self::Ownership> {
46+
use core::mem::ManuallyDrop;
47+
4648
use objc2_block::{Block, ConcreteBlock};
4749

4850
let capacity = bytes.capacity();
51+
4952
let dealloc = ConcreteBlock::new(move |bytes: *mut c_void, len: usize| unsafe {
5053
// Recreate the Vec and let it drop
5154
let _ = Vec::from_raw_parts(bytes as *mut u8, len, capacity);
5255
});
5356
let dealloc = dealloc.copy();
5457
let dealloc: &Block<(*mut c_void, usize), ()> = &dealloc;
5558

56-
let mut bytes = bytes;
57-
let bytes_ptr = bytes.as_mut_ptr() as *mut c_void;
58-
5959
// GNUStep's NSData `initWithBytesNoCopy:length:deallocator:` has a
6060
// bug; it forgets to assign the input buffer and length to the
6161
// instance before it swizzles to NSDataWithDeallocatorBlock.
@@ -72,15 +72,17 @@ pub unsafe trait INSData: INSObject {
7272
};
7373
#[cfg(not(gnustep))]
7474
let cls = Self::class();
75+
76+
let mut bytes = ManuallyDrop::new(bytes);
77+
7578
unsafe {
7679
let obj: *mut Self = msg_send![cls, alloc];
7780
let obj: *mut Self = msg_send![
7881
obj,
79-
initWithBytesNoCopy: bytes_ptr,
82+
initWithBytesNoCopy: bytes.as_mut_ptr() as *mut c_void,
8083
length: bytes.len(),
8184
deallocator: dealloc,
8285
];
83-
core::mem::forget(bytes);
8486
Id::new(NonNull::new_unchecked(obj))
8587
}
8688
}
@@ -98,45 +100,45 @@ unsafe impl INSMutableCopying for NSData {
98100
type Output = NSMutableData;
99101
}
100102

103+
impl Deref for NSData {
104+
type Target = [u8];
105+
106+
fn deref(&self) -> &[u8] {
107+
self.bytes()
108+
}
109+
}
110+
101111
pub unsafe trait INSMutableData: INSData {
102112
fn bytes_mut(&mut self) -> &mut [u8] {
103113
let ptr: *mut c_void = unsafe { msg_send![self, mutableBytes] };
104114
// The bytes pointer may be null for length zero
105-
let (ptr, len) = if ptr.is_null() {
106-
(0x1 as *mut u8, 0)
115+
if ptr.is_null() {
116+
&mut []
107117
} else {
108-
(ptr as *mut u8, self.len())
109-
};
110-
unsafe { slice::from_raw_parts_mut(ptr, len) }
118+
unsafe { slice::from_raw_parts_mut(ptr as *mut u8, self.len()) }
119+
}
111120
}
112121

122+
/// Expands with zeroes, or truncates the buffer.
113123
fn set_len(&mut self, len: usize) {
114-
unsafe {
115-
let _: () = msg_send![self, setLength: len];
116-
}
124+
unsafe { msg_send![self, setLength: len] }
117125
}
118126

119127
fn append(&mut self, bytes: &[u8]) {
120128
let bytes_ptr = bytes.as_ptr() as *const c_void;
121-
unsafe {
122-
let _: () = msg_send![
123-
self,
124-
appendBytes: bytes_ptr,
125-
length:bytes.len(),
126-
];
127-
}
129+
unsafe { msg_send![self, appendBytes: bytes_ptr, length: bytes.len()] }
128130
}
129131

130132
fn replace_range(&mut self, range: Range<usize>, bytes: &[u8]) {
131133
let range = NSRange::from(range);
132-
let bytes_ptr = bytes.as_ptr() as *const c_void;
134+
let ptr = bytes.as_ptr() as *const c_void;
133135
unsafe {
134-
let _: () = msg_send![
136+
msg_send![
135137
self,
136-
replaceBytesInRange:range,
137-
withBytes:bytes_ptr,
138-
length:bytes.len(),
139-
];
138+
replaceBytesInRange: range,
139+
withBytes: ptr,
140+
length: bytes.len(),
141+
]
140142
}
141143
}
142144

@@ -160,6 +162,20 @@ unsafe impl INSMutableCopying for NSMutableData {
160162
type Output = NSMutableData;
161163
}
162164

165+
impl Deref for NSMutableData {
166+
type Target = [u8];
167+
168+
fn deref(&self) -> &[u8] {
169+
self.bytes()
170+
}
171+
}
172+
173+
impl DerefMut for NSMutableData {
174+
fn deref_mut(&mut self) -> &mut [u8] {
175+
self.bytes_mut()
176+
}
177+
}
178+
163179
#[cfg(test)]
164180
mod tests {
165181
use super::{INSData, INSMutableData, NSData, NSMutableData};
@@ -171,8 +187,8 @@ mod tests {
171187
fn test_bytes() {
172188
let bytes = [3, 7, 16, 52, 112, 19];
173189
let data = NSData::with_bytes(&bytes);
174-
assert!(data.len() == bytes.len());
175-
assert!(data.bytes() == bytes);
190+
assert_eq!(data.len(), bytes.len());
191+
assert_eq!(data.bytes(), bytes);
176192
}
177193

178194
#[test]
@@ -185,43 +201,43 @@ mod tests {
185201
fn test_bytes_mut() {
186202
let mut data = NSMutableData::with_bytes(&[7, 16]);
187203
data.bytes_mut()[0] = 3;
188-
assert!(data.bytes() == [3, 16]);
204+
assert_eq!(data.bytes(), [3, 16]);
189205
}
190206

191207
#[test]
192208
fn test_set_len() {
193209
let mut data = NSMutableData::with_bytes(&[7, 16]);
194210
data.set_len(4);
195-
assert!(data.len() == 4);
196-
assert!(data.bytes() == [7, 16, 0, 0]);
211+
assert_eq!(data.len(), 4);
212+
assert_eq!(data.bytes(), [7, 16, 0, 0]);
197213

198214
data.set_len(1);
199-
assert!(data.len() == 1);
200-
assert!(data.bytes() == [7]);
215+
assert_eq!(data.len(), 1);
216+
assert_eq!(data.bytes(), [7]);
201217
}
202218

203219
#[test]
204220
fn test_append() {
205221
let mut data = NSMutableData::with_bytes(&[7, 16]);
206222
data.append(&[3, 52]);
207-
assert!(data.len() == 4);
208-
assert!(data.bytes() == [7, 16, 3, 52]);
223+
assert_eq!(data.len(), 4);
224+
assert_eq!(data.bytes(), [7, 16, 3, 52]);
209225
}
210226

211227
#[test]
212228
fn test_replace() {
213229
let mut data = NSMutableData::with_bytes(&[7, 16]);
214230
data.replace_range(0..0, &[3]);
215-
assert!(data.bytes() == [3, 7, 16]);
231+
assert_eq!(data.bytes(), [3, 7, 16]);
216232

217233
data.replace_range(1..2, &[52, 13]);
218-
assert!(data.bytes() == [3, 52, 13, 16]);
234+
assert_eq!(data.bytes(), [3, 52, 13, 16]);
219235

220236
data.replace_range(2..4, &[6]);
221-
assert!(data.bytes() == [3, 52, 6]);
237+
assert_eq!(data.bytes(), [3, 52, 6]);
222238

223239
data.set_bytes(&[8, 17]);
224-
assert!(data.bytes() == [8, 17]);
240+
assert_eq!(data.bytes(), [8, 17]);
225241
}
226242

227243
#[cfg(feature = "block")]

0 commit comments

Comments
 (0)