Skip to content

Commit 4d3af41

Browse files
committed
Add a few safe NSValue getters
1 parent 29d26f5 commit 4d3af41

File tree

3 files changed

+89
-12
lines changed

3 files changed

+89
-12
lines changed

objc2/CHANGELOG_FOUNDATION.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1717
* Add extra `Extend<&u8>` impl for `NSMutableData`.
1818
* Added function `NSValue::contains_encoding` for determining if the encoding
1919
of the `NSValue` matches the encoding of the given type.
20+
* Added functions `get_range`, `get_point`, `get_size` and `get_rect` to
21+
`NSValue` to help safely returning various types it will commonly contain.
2022

2123
### Changed
2224
* **BREAKING**: Moved from external crate `objc2_foundation` into

objc2/src/foundation/geometry.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ pub type CGFloat = InnerFloat;
2525
not(all(target_os = "macos", target_pointer_width = "32"))
2626
))]
2727
mod names {
28-
pub(super) const POINT: &str = "_CGPoint";
29-
pub(super) const SIZE: &str = "_CGSize";
30-
pub(super) const RECT: &str = "_CGRect";
28+
pub(super) const POINT: &str = "CGPoint";
29+
pub(super) const SIZE: &str = "CGSize";
30+
pub(super) const RECT: &str = "CGRect";
3131
}
3232

3333
#[cfg(any(

objc2/src/foundation/value.rs

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use core::str;
88
use std::ffi::{CStr, CString};
99
use std::os::raw::c_char;
1010

11-
use super::{NSCopying, NSObject};
11+
use super::{NSCopying, NSObject, NSPoint, NSRange, NSRect, NSSize};
1212
use crate::rc::{Id, Shared};
1313
use crate::Encode;
1414
use crate::{extern_class, msg_send, msg_send_bool, msg_send_id};
@@ -129,6 +129,54 @@ impl NSValue {
129129
unsafe { value.assume_init() }
130130
}
131131

132+
pub fn get_range(&self) -> Option<NSRange> {
133+
if self.contains_encoding::<NSRange>() {
134+
// SAFETY: We just checked that this contains an NSRange
135+
Some(unsafe { msg_send![self, rangeValue] })
136+
} else {
137+
None
138+
}
139+
}
140+
141+
pub fn get_point(&self) -> Option<NSPoint> {
142+
if self.contains_encoding::<NSPoint>() {
143+
// SAFETY: We just checked that this contains an NSPoint
144+
#[cfg(any(feature = "gnustep-1-7", target_os = "macos"))]
145+
let res = unsafe { msg_send![self, pointValue] };
146+
#[cfg(all(feature = "apple", not(target_os = "macos")))]
147+
let res = unsafe { msg_send![self, CGPointValue] };
148+
Some(res)
149+
} else {
150+
None
151+
}
152+
}
153+
154+
pub fn get_size(&self) -> Option<NSSize> {
155+
if self.contains_encoding::<NSSize>() {
156+
// SAFETY: We just checked that this contains an NSSize
157+
#[cfg(any(feature = "gnustep-1-7", target_os = "macos"))]
158+
let res = unsafe { msg_send![self, sizeValue] };
159+
#[cfg(all(feature = "apple", not(target_os = "macos")))]
160+
let res = unsafe { msg_send![self, CGSizeValue] };
161+
Some(res)
162+
} else {
163+
None
164+
}
165+
}
166+
167+
pub fn get_rect(&self) -> Option<NSRect> {
168+
if self.contains_encoding::<NSRect>() {
169+
// SAFETY: We just checked that this contains an NSRect
170+
#[cfg(any(feature = "gnustep-1-7", target_os = "macos"))]
171+
let res = unsafe { msg_send![self, rectValue] };
172+
#[cfg(all(feature = "apple", not(target_os = "macos")))]
173+
let res = unsafe { msg_send![self, CGRectValue] };
174+
Some(res)
175+
} else {
176+
None
177+
}
178+
}
179+
132180
pub fn encoding(&self) -> Option<&str> {
133181
let result: Option<NonNull<c_char>> = unsafe { msg_send![self, objCType] };
134182
result.map(|s| unsafe { CStr::from_ptr(s.as_ptr()) }.to_str().unwrap())
@@ -187,8 +235,6 @@ mod tests {
187235
use core::slice;
188236

189237
use super::*;
190-
use crate::foundation::NSRange;
191-
use crate::msg_send;
192238

193239
#[test]
194240
fn basic() {
@@ -230,14 +276,43 @@ mod tests {
230276
}
231277

232278
#[test]
233-
fn test_value_nsrange() {
234-
let val = NSValue::new(NSRange::from(1..2));
235-
assert!(val.contains_encoding::<NSRange>());
236-
let range: NSRange = unsafe { msg_send![&val, rangeValue] };
237-
assert_eq!(range, NSRange::from(1..2));
279+
fn nsrange() {
280+
let range = NSRange::from(1..2);
281+
let val = NSValue::new(range);
282+
assert_eq!(val.get_range(), Some(range));
283+
assert_eq!(val.get_point(), None);
284+
assert_eq!(val.get_size(), None);
285+
assert_eq!(val.get_rect(), None);
238286
// NSValue -getValue is broken on GNUStep for some types
239287
#[cfg(not(feature = "gnustep-1-7"))]
240-
assert_eq!(unsafe { val.get::<NSRange>() }, NSRange::from(1..2));
288+
assert_eq!(unsafe { val.get::<NSRange>() }, range);
289+
}
290+
291+
#[test]
292+
fn nspoint() {
293+
let point = NSPoint::new(1.0, 2.0);
294+
let val = NSValue::new(point);
295+
assert_eq!(val.get_point(), Some(point));
296+
#[cfg(not(feature = "gnustep-1-7"))]
297+
assert_eq!(unsafe { val.get::<NSPoint>() }, point);
298+
}
299+
300+
#[test]
301+
fn nssize() {
302+
let point = NSSize::new(1.0, 2.0);
303+
let val = NSValue::new(point);
304+
assert_eq!(val.get_size(), Some(point));
305+
#[cfg(not(feature = "gnustep-1-7"))]
306+
assert_eq!(unsafe { val.get::<NSSize>() }, point);
307+
}
308+
309+
#[test]
310+
fn nsrect() {
311+
let rect = NSRect::new(NSPoint::new(1.0, 2.0), NSSize::new(3.0, 4.0));
312+
let val = NSValue::new(rect);
313+
assert_eq!(val.get_rect(), Some(rect));
314+
#[cfg(not(feature = "gnustep-1-7"))]
315+
assert_eq!(unsafe { val.get::<NSRect>() }, rect);
241316
}
242317

243318
#[test]

0 commit comments

Comments
 (0)