Skip to content

Commit c0b7df0

Browse files
authored
Merge pull request #116 from madsmtm/helper-functions
Add a few helper functions
2 parents 62686bc + 2f26ed6 commit c0b7df0

File tree

10 files changed

+83
-23
lines changed

10 files changed

+83
-23
lines changed

objc2-foundation/src/object.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub unsafe trait INSObject: Message {
1717

1818
fn is_equal<T: INSObject>(&self, other: &T) -> bool {
1919
let result: Bool = unsafe { msg_send![self, isEqual: other] };
20-
result.is_true()
20+
result.as_bool()
2121
}
2222

2323
fn description(&self) -> Id<NSString, Shared> {
@@ -30,7 +30,7 @@ pub unsafe trait INSObject: Message {
3030

3131
fn is_kind_of(&self, cls: &Class) -> bool {
3232
let result: Bool = unsafe { msg_send![self, isKindOfClass: cls] };
33-
result.is_true()
33+
result.as_bool()
3434
}
3535
}
3636

objc2/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1010
* Added deprecated `Object::get_ivar` and `Object::get_mut_ivar` to make
1111
upgrading easier.
1212
* Allow using `From`/`TryFrom` to convert between `rc::Id` and `rc::WeakId`.
13+
* Added `Bool::as_bool` (more descriptive name than `Bool::is_true`).
14+
* Added convenience methods `Id::new_null`, `Id::as_ptr` and
15+
`Id::retain_null`.
1316

1417

1518
## 0.3.0-alpha.6 - 2022-01-03

objc2/src/bool.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use core::fmt;
44
/// The Objective-C `BOOL` type.
55
///
66
/// This is a thin wrapper-type over [`objc_sys::BOOL`]. It is intended that
7-
/// you convert this into a Rust [`bool`] with the [`Bool::is_false`] or
8-
/// [`Bool::is_true`] methods as soon as possible.
7+
/// you convert this into a Rust [`bool`] with the [`Bool::as_bool`] method as
8+
/// soon as possible.
99
///
1010
/// This is FFI-safe and can be used in directly with
1111
/// [`msg_send!`][`crate::msg_send`].
@@ -20,12 +20,12 @@ use core::fmt;
2020
/// use objc2::runtime::{Object, Bool};
2121
/// let ns_value: *mut Object = unsafe { msg_send![class!(NSValue), initWithBool: Bool::YES] };
2222
/// let rtn: Bool = unsafe { msg_send![ns_value, boolValue] };
23-
/// assert!(rtn.is_true());
23+
/// assert!(rtn.as_bool());
2424
/// ```
2525
#[repr(transparent)]
2626
// We don't implement comparison traits because they could be implemented with
2727
// two slightly different semantics:
28-
// - `self.is_true().cmp(other.is_true())`
28+
// - `self.as_bool().cmp(other.as_bool())`
2929
// - `self.value.cmp(other.value)`
3030
// And it is not immediately clear for users which one was chosen.
3131
#[derive(Copy, Clone, Default)]
@@ -63,6 +63,8 @@ impl Bool {
6363
}
6464

6565
/// Returns `true` if `self` is [`NO`][`Self::NO`].
66+
///
67+
/// You should prefer using [`as_bool`][`Self::as_bool`].
6668
#[inline]
6769
pub const fn is_false(self) -> bool {
6870
// Always compare with 0
@@ -71,12 +73,20 @@ impl Bool {
7173
}
7274

7375
/// Returns `true` if `self` is the opposite of [`NO`][`Self::NO`].
76+
///
77+
/// You should prefer using [`as_bool`][`Self::as_bool`].
7478
#[inline]
7579
pub const fn is_true(self) -> bool {
7680
// Always compare with 0
7781
// This is what happens when using `if` in C.
7882
self.value as u8 != 0
7983
}
84+
85+
/// Converts this into the [`bool`] equivalent.
86+
#[inline]
87+
pub const fn as_bool(self) -> bool {
88+
self.is_true()
89+
}
8090
}
8191

8292
impl From<bool> for Bool {
@@ -89,13 +99,13 @@ impl From<bool> for Bool {
8999
impl From<Bool> for bool {
90100
#[inline]
91101
fn from(b: Bool) -> bool {
92-
b.is_true()
102+
b.as_bool()
93103
}
94104
}
95105

96106
impl fmt::Debug for Bool {
97107
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98-
f.write_str(if self.is_true() { "YES" } else { "NO" })
108+
f.write_str(if self.as_bool() { "YES" } else { "NO" })
99109
}
100110
}
101111

@@ -125,12 +135,14 @@ mod tests {
125135
#[test]
126136
fn test_basic() {
127137
let b = Bool::new(true);
138+
assert!(b.as_bool());
128139
assert!(b.is_true());
129140
assert!(!b.is_false());
130141
assert!(bool::from(b));
131142
assert_eq!(b.as_raw() as usize, 1);
132143

133144
let b = Bool::new(false);
145+
assert!(!b.as_bool());
134146
assert!(!b.is_true());
135147
assert!(b.is_false());
136148
assert!(!bool::from(b));
@@ -140,19 +152,23 @@ mod tests {
140152
#[test]
141153
fn test_associated_constants() {
142154
let b = Bool::YES;
155+
assert!(b.as_bool());
143156
assert!(b.is_true());
144157
assert_eq!(b.as_raw() as usize, 1);
145158

146159
let b = Bool::NO;
160+
assert!(!b.as_bool());
147161
assert!(b.is_false());
148162
assert_eq!(b.as_raw() as usize, 0);
149163
}
150164

151165
#[test]
152166
fn test_impls() {
153167
let b: Bool = Default::default();
168+
assert!(!b.as_bool());
154169
assert!(b.is_false());
155170

171+
assert!(Bool::from(true).as_bool());
156172
assert!(Bool::from(true).is_true());
157173
assert!(Bool::from(false).is_false());
158174

objc2/src/declare.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl ClassDecl {
215215
types.as_ptr(),
216216
)
217217
});
218-
assert!(success.is_true(), "Failed to add method {:?}", sel);
218+
assert!(success.as_bool(), "Failed to add method {:?}", sel);
219219
}
220220

221221
/// Adds a class method with the given name and implementation.
@@ -253,7 +253,7 @@ impl ClassDecl {
253253
types.as_ptr(),
254254
)
255255
});
256-
assert!(success.is_true(), "Failed to add class method {:?}", sel);
256+
assert!(success.as_bool(), "Failed to add class method {:?}", sel);
257257
}
258258

259259
/// Adds an ivar with type `T` and the provided name.
@@ -275,7 +275,7 @@ impl ClassDecl {
275275
encoding.as_ptr(),
276276
)
277277
});
278-
assert!(success.is_true(), "Failed to add ivar {}", name);
278+
assert!(success.as_bool(), "Failed to add ivar {}", name);
279279
}
280280

281281
/// Adds the given protocol to self.
@@ -285,7 +285,7 @@ impl ClassDecl {
285285
/// If the protocol wasn't successfully added.
286286
pub fn add_protocol(&mut self, proto: &Protocol) {
287287
let success = unsafe { ffi::class_addProtocol(self.cls as _, proto.as_ptr()) };
288-
let success = Bool::from_raw(success).is_true();
288+
let success = Bool::from_raw(success).as_bool();
289289
assert!(success, "Failed to add protocol {:?}", proto);
290290
}
291291

objc2/src/exception.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ extern "C" {
6868
#[inline]
6969
pub unsafe fn throw(exception: Option<&Id<Object, Shared>>) -> ! {
7070
let exception = match exception {
71-
Some(id) => &**id as *const Object as *mut ffi::objc_object,
71+
Some(id) => id.as_ptr() as *mut ffi::objc_object,
7272
None => ptr::null_mut(),
7373
};
7474
unsafe { ffi::objc_exception_throw(exception) }

objc2/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
//! // Usage
4545
//! let hash: NSUInteger = unsafe { msg_send![obj, hash] };
4646
//! let is_kind: Bool = unsafe { msg_send![obj, isKindOfClass: cls] };
47-
//! assert!(is_kind.is_true());
47+
//! assert!(is_kind.as_bool());
4848
//! ```
4949
//!
5050
//! Note that this very simple example contains **a lot** of `unsafe` (which

objc2/src/message/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,7 @@ unsafe impl<T: Message + ?Sized> MessageReceiver for NonNull<T> {
252252
unsafe impl<T: Message + ?Sized, O: Ownership> MessageReceiver for Id<T, O> {
253253
#[inline]
254254
fn as_raw_receiver(&self) -> *mut Object {
255-
// TODO: Maybe don't dereference here, just to be safe?
256-
(&**self).as_raw_receiver()
255+
self.as_ptr() as *mut Object
257256
}
258257
}
259258

@@ -449,7 +448,7 @@ mod tests {
449448
};
450449
assert_eq!(result, 4);
451450

452-
let obj: *const ManuallyDrop<Object> = (&**obj as *const Object).cast();
451+
let obj: *const ManuallyDrop<Object> = obj.as_ptr().cast();
453452
let result: u32 = unsafe { msg_send![obj, foo] };
454453
assert_eq!(result, 4);
455454
}

objc2/src/rc/id.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,33 @@ impl<T: Message + ?Sized, O: Ownership> Id<T, O> {
173173
own: PhantomData,
174174
}
175175
}
176+
177+
/// Constructs an [`Id`] from a pointer that may be null.
178+
///
179+
/// This is just a convenience wrapper over [`Id::new`] so that you don't
180+
/// need to construct a [`NonNull`] when you know the pointer may be null.
181+
///
182+
/// # Safety
183+
///
184+
/// Same as [`Id::new`].
185+
#[inline]
186+
pub unsafe fn new_null(ptr: *mut T) -> Option<Id<T, O>> {
187+
// SAFETY: Upheld by the caller
188+
NonNull::new(ptr).map(|ptr| unsafe { Id::new(ptr) })
189+
}
190+
191+
/// Returns a raw pointer to the object.
192+
///
193+
/// The pointer is valid for at least as long as the `Id` is held.
194+
#[inline]
195+
pub fn as_ptr(&self) -> *mut T {
196+
// Note: This is not an associated function, which breaks the
197+
// guideline that smart pointers shouldn't add inherent methods!
198+
//
199+
// However, this method is quite useful when migrating old codebases,
200+
// so I think we'll let it be here for now.
201+
self.ptr.as_ptr()
202+
}
176203
}
177204

178205
// TODO: Add ?Sized bound
@@ -224,6 +251,21 @@ impl<T: Message, O: Ownership> Id<T, O> {
224251
unsafe { Self::new(res) }
225252
}
226253

254+
/// Retains an object pointer that may be null.
255+
///
256+
/// This is just a convenience wrapper over [`Id::retain`] so that you
257+
/// don't need to construct a [`NonNull`] when you know the pointer may
258+
/// be null.
259+
///
260+
/// # Safety
261+
///
262+
/// Same as [`Id::retain`].
263+
#[inline]
264+
pub unsafe fn retain_null(ptr: *mut T) -> Option<Id<T, O>> {
265+
// SAFETY: Upheld by the caller
266+
NonNull::new(ptr).map(|ptr| unsafe { Id::retain(ptr) })
267+
}
268+
227269
#[cfg_attr(not(debug_assertions), inline)]
228270
fn autorelease_inner(self) -> *mut T {
229271
// Note that this (and the actual `autorelease`) is not an associated
@@ -232,7 +274,7 @@ impl<T: Message, O: Ownership> Id<T, O> {
232274
// retained objects it is hard to imagine a case where the inner type
233275
// has a method with the same name.
234276

235-
let ptr = ManuallyDrop::new(self).ptr.as_ptr() as *mut ffi::objc_object;
277+
let ptr = ManuallyDrop::new(self).as_ptr() as *mut ffi::objc_object;
236278
// SAFETY: The `ptr` is guaranteed to be valid and have at least one
237279
// retain count.
238280
// And because of the ManuallyDrop, we don't call the Drop

objc2/src/rc/weak_id.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl<T: Message> WeakId<T> {
4040
// allow loading an `Id<T, Shared>` later on.
4141

4242
// SAFETY: `obj` is valid
43-
unsafe { Self::new_inner(&**obj as *const T as *mut T) }
43+
unsafe { Self::new_inner(obj.as_ptr()) }
4444
}
4545

4646
/// # Safety

objc2/src/runtime.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ impl Class {
309309

310310
#[allow(unused)]
311311
fn is_metaclass(&self) -> bool {
312-
unsafe { Bool::from_raw(ffi::class_isMetaClass(self.as_ptr())).is_true() }
312+
unsafe { Bool::from_raw(ffi::class_isMetaClass(self.as_ptr())).as_bool() }
313313
}
314314

315315
/// Returns the size of instances of self.
@@ -378,7 +378,7 @@ impl Class {
378378
/// Checks whether this class conforms to the specified protocol.
379379
pub fn conforms_to(&self, proto: &Protocol) -> bool {
380380
unsafe {
381-
Bool::from_raw(ffi::class_conformsToProtocol(self.as_ptr(), proto.as_ptr())).is_true()
381+
Bool::from_raw(ffi::class_conformsToProtocol(self.as_ptr(), proto.as_ptr())).as_bool()
382382
}
383383
}
384384

@@ -478,7 +478,7 @@ impl Protocol {
478478
self.as_ptr(),
479479
proto.as_ptr(),
480480
))
481-
.is_true()
481+
.as_bool()
482482
}
483483
}
484484

@@ -493,7 +493,7 @@ impl PartialEq for Protocol {
493493
/// Check whether the protocols are equal, or conform to each other.
494494
#[inline]
495495
fn eq(&self, other: &Protocol) -> bool {
496-
unsafe { Bool::from_raw(ffi::protocol_isEqual(self.as_ptr(), other.as_ptr())).is_true() }
496+
unsafe { Bool::from_raw(ffi::protocol_isEqual(self.as_ptr(), other.as_ptr())).as_bool() }
497497
}
498498
}
499499

0 commit comments

Comments
 (0)