Skip to content

Commit 985b784

Browse files
committed
Fix INSData::from_vec on GNUStep
NSData initWithBytesNoCopy:length:deallocator: is broken in GNUStep, see gnustep/libs-base#213
1 parent 8577599 commit 985b784

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

objc2_foundation/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ repository = "https://github.com/madsmtm/objc2"
1616
documentation = "https://docs.rs/objc2_foundation/"
1717
license = "MIT"
1818

19+
build = "build.rs"
20+
1921
[features]
2022
default = ["block"]
2123
# Provided as a way to cut down on dependencies
@@ -24,3 +26,4 @@ block = ["objc2_block"]
2426
[dependencies]
2527
objc2_block = { path = "../objc2_block", optional = true }
2628
objc2 = { path = "../objc2" }
29+
objc2_sys = { path = "../objc2_sys" }

objc2_foundation/build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use std::env;
2+
3+
fn main() {
4+
// The script doesn't depend on our code
5+
println!("cargo:rerun-if-changed=build.rs");
6+
7+
let runtime = env::var("DEP_OBJC_RUNTIME").unwrap();
8+
println!("cargo:rustc-cfg={}", runtime);
9+
}

objc2_foundation/src/data.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ use core::{ffi::c_void, ptr::NonNull};
77
use super::{INSCopying, INSMutableCopying, INSObject, NSRange};
88
use objc2::msg_send;
99
use objc2::rc::{Id, Owned};
10-
#[cfg(feature = "block")]
11-
use objc2_block::{Block, ConcreteBlock};
1210

1311
pub trait INSData: INSObject {
1412
fn len(&self) -> usize {
@@ -22,12 +20,11 @@ pub trait INSData: INSObject {
2220
fn bytes(&self) -> &[u8] {
2321
let ptr: *const c_void = unsafe { msg_send![self, bytes] };
2422
// The bytes pointer may be null for length zero
25-
let (ptr, len) = if ptr.is_null() {
26-
(0x1 as *const u8, 0)
23+
if ptr.is_null() {
24+
&[]
2725
} else {
28-
(ptr as *const u8, self.len())
29-
};
30-
unsafe { slice::from_raw_parts(ptr, len) }
26+
unsafe { slice::from_raw_parts(ptr as *const u8, self.len()) }
27+
}
3128
}
3229

3330
fn with_bytes(bytes: &[u8]) -> Id<Self, Owned> {
@@ -46,6 +43,8 @@ pub trait INSData: INSObject {
4643

4744
#[cfg(feature = "block")]
4845
fn from_vec(bytes: Vec<u8>) -> Id<Self, Owned> {
46+
use objc2_block::{Block, ConcreteBlock};
47+
4948
let capacity = bytes.capacity();
5049
let dealloc = ConcreteBlock::new(move |bytes: *mut c_void, len: usize| unsafe {
5150
// Recreate the Vec and let it drop
@@ -56,6 +55,22 @@ pub trait INSData: INSObject {
5655

5756
let mut bytes = bytes;
5857
let bytes_ptr = bytes.as_mut_ptr() as *mut c_void;
58+
59+
// GNUStep's NSData `initWithBytesNoCopy:length:deallocator:` has a
60+
// bug; it forgets to assign the input buffer and length to the
61+
// instance before it swizzles to NSDataWithDeallocatorBlock.
62+
// See https://github.com/gnustep/libs-base/pull/213
63+
// So we just use NSDataWithDeallocatorBlock directly.
64+
#[cfg(gnustep)]
65+
let cls = {
66+
let cls = Self::class();
67+
if cls == objc2::class!(NSData) {
68+
objc2::class!(NSDataWithDeallocatorBlock)
69+
} else {
70+
cls
71+
}
72+
};
73+
#[cfg(not(gnustep))]
5974
let cls = Self::class();
6075
unsafe {
6176
let obj: *mut Self = msg_send![cls, alloc];
@@ -216,6 +231,6 @@ mod tests {
216231
let bytes_ptr = bytes.as_ptr();
217232

218233
let data = NSData::from_vec(bytes);
219-
assert!(data.bytes().as_ptr() == bytes_ptr);
234+
assert_eq!(data.bytes().as_ptr(), bytes_ptr);
220235
}
221236
}

0 commit comments

Comments
 (0)