Skip to content

Commit 43c1d8a

Browse files
authored
Merge pull request #239 from madsmtm/bool-handling
Proper `bool` handling
2 parents 04787a3 + dee955d commit 43c1d8a

40 files changed

+825
-661
lines changed

block2/Cargo.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ std = ["alloc", "objc2-encode/std", "block-sys/std"]
2525
alloc = ["objc2-encode/alloc", "block-sys/alloc"]
2626

2727
# Runtime selection. Default is `apple`. See `block-sys` for details.
28-
apple = ["block-sys/apple"]
29-
compiler-rt = ["block-sys/compiler-rt"]
30-
gnustep-1-7 = ["block-sys/gnustep-1-7"]
31-
gnustep-1-8 = ["gnustep-1-7", "block-sys/gnustep-1-8"]
32-
gnustep-1-9 = ["gnustep-1-8", "block-sys/gnustep-1-9"]
33-
gnustep-2-0 = ["gnustep-1-9", "block-sys/gnustep-2-0"]
34-
gnustep-2-1 = ["gnustep-2-0", "block-sys/gnustep-2-1"]
28+
apple = ["block-sys/apple", "objc2-encode/apple"]
29+
compiler-rt = ["block-sys/compiler-rt", "objc2-encode/apple"] # Use Apple's encoding
30+
gnustep-1-7 = ["block-sys/gnustep-1-7", "objc2-encode/gnustep-1-7"]
31+
gnustep-1-8 = ["gnustep-1-7", "block-sys/gnustep-1-8", "objc2-encode/gnustep-1-8"]
32+
gnustep-1-9 = ["gnustep-1-8", "block-sys/gnustep-1-9", "objc2-encode/gnustep-1-9"]
33+
gnustep-2-0 = ["gnustep-1-9", "block-sys/gnustep-2-0", "objc2-encode/gnustep-2-0"]
34+
gnustep-2-1 = ["gnustep-2-0", "block-sys/gnustep-2-1", "objc2-encode/gnustep-2-1"]
3535

3636
[dependencies]
3737
objc2-encode = { path = "../objc2-encode", version = "=2.0.0-pre.1", default-features = false }

objc-sys/src/types.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,11 @@ mod inner {
6868
/// The Objective-C `BOOL` type.
6969
///
7070
/// The type of this varies across platforms, so to convert an it into a Rust
71-
/// [`bool`], always compare it with [`YES`][`crate::YES`] or [`NO`][`crate::NO`].
71+
/// [`bool`], compare it with [`NO`][crate::NO].
7272
///
73-
/// Note that this type implements `objc2_encode::Encode` and
74-
/// `objc2_encode::RefEncode`, but the `RefEncode` implementation is wrong
75-
/// on some platforms! You should only use this on FFI boundaries, otherwise
76-
/// prefer `objc2::runtime::Bool`.
73+
/// Note that this does _not_ implement `objc2::Encode` on all platforms! You
74+
/// should only use this on FFI boundaries, otherwise prefer
75+
/// `objc2::runtime::Bool`.
7776
///
7877
/// See also the [corresponding documentation entry][docs].
7978
///

objc2-encode/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## Unreleased - YYYY-MM-DD
88

9+
### Added
10+
* Added `EncodeConvert` trait to help with correctly handling `BOOL`/`bool`.
11+
912
### Changed
1013
* **BREAKING**: Remove the lifetime specifier from `Encoding`, since the non
1114
-`'static` version was essentially useless.
1215

1316
### Fixed
1417
* Fixed the encoding output and comparison of structs behind pointers.
1518

19+
### Removed
20+
* **BREAKING**: `bool` (and `AtomicBool`) no longer implements `Encode`, since
21+
that was difficult to use correctly. See the `EncodeConvert` trait, or use
22+
`objc2::runtime::Bool` instead.
23+
1624

1725
## 2.0.0-pre.1 - 2022-07-19
1826

objc2-encode/Cargo.toml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,28 @@ documentation = "https://docs.rs/objc2-encode/"
1919
license = "MIT"
2020

2121
[features]
22-
default = ["std"]
22+
default = ["std", "apple"]
2323

24-
# Doesn't do anything (this crate works on no_std), put here for forwards
25-
# compatibility.
26-
std = ["alloc"]
27-
alloc = []
24+
# Currently not possible to turn off, put here for forwards compatibility.
25+
std = ["alloc", "objc-sys/std"]
26+
alloc = ["objc-sys/alloc"]
2827

2928
# Enables support for the nightly c_unwind feature
3029
unstable-c-unwind = []
3130

31+
# Runtime selection. See `objc-sys` for details.
32+
apple = ["objc-sys/apple"]
33+
gnustep-1-7 = ["objc-sys/gnustep-1-7"]
34+
gnustep-1-8 = ["gnustep-1-7", "objc-sys/gnustep-1-8"]
35+
gnustep-1-9 = ["gnustep-1-8", "objc-sys/gnustep-1-9"]
36+
gnustep-2-0 = ["gnustep-1-9", "objc-sys/gnustep-2-0"]
37+
gnustep-2-1 = ["gnustep-2-0", "objc-sys/gnustep-2-1"]
38+
39+
[dependencies]
40+
# TODO: Remove this dependency when we can select `macabi` targets separately
41+
# from other targets without using a build script
42+
objc-sys = { path = "../objc-sys", version = "=0.2.0-beta.1", default-features = false }
43+
3244
[package.metadata.docs.rs]
3345
default-target = "x86_64-apple-darwin"
3446

objc2/src/bool.rs renamed to objc2-encode/src/__bool.rs

Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,20 @@
1-
use crate::{ffi, Encode, Encoding, RefEncode};
1+
//! This belongs in `objc2`, but it is put here to make `EncodeConvert` work
2+
//! properly!
23
use core::fmt;
34

5+
use crate::{Encode, EncodeConvert, Encoding, RefEncode};
6+
47
/// The Objective-C `BOOL` type.
58
///
69
/// This is a thin wrapper-type over [`objc_sys::BOOL`]. It is intended that
710
/// you convert this into a Rust [`bool`] with the [`Bool::as_bool`] method as
811
/// soon as possible.
912
///
10-
/// This is FFI-safe and can be used in directly with
11-
/// [`msg_send!`][`crate::msg_send`].
13+
/// This is FFI-safe and can be used directly with `msg_send!` and `extern`
14+
/// functions.
1215
///
1316
/// Note that this is able to contain more states than `bool` on some
1417
/// platforms, but these cases should not be relied on!
15-
///
16-
/// # Example
17-
///
18-
/// ```no_run
19-
/// use objc2::{class, msg_send_bool, msg_send_id};
20-
/// use objc2::rc::{Id, Shared};
21-
/// use objc2::runtime::{Object, Bool};
22-
/// let ns_value: Id<Object, Shared> = unsafe {
23-
/// msg_send_id![class!(NSNumber), numberWithBool: Bool::YES]
24-
/// };
25-
/// assert!(unsafe { msg_send_bool![&ns_value, boolValue] });
26-
/// ```
2718
#[repr(transparent)]
2819
// We don't implement comparison traits because they could be implemented with
2920
// two slightly different semantics:
@@ -32,62 +23,60 @@ use core::fmt;
3223
// And it is not immediately clear for users which one was chosen.
3324
#[derive(Copy, Clone, Default)]
3425
pub struct Bool {
35-
value: ffi::BOOL,
26+
value: objc_sys::BOOL,
3627
}
3728

3829
impl Bool {
3930
/// The equivalent of [`true`] for Objective-C's `BOOL` type.
40-
pub const YES: Self = Self::from_raw(ffi::YES);
31+
pub const YES: Self = Self::from_raw(objc_sys::YES);
4132

4233
/// The equivalent of [`false`] for Objective-C's `BOOL` type.
43-
pub const NO: Self = Self::from_raw(ffi::NO);
34+
pub const NO: Self = Self::from_raw(objc_sys::NO);
4435

4536
/// Creates an Objective-C boolean from a Rust boolean.
4637
#[inline]
4738
pub const fn new(value: bool) -> Self {
48-
// true as u8 => 1
49-
// false as u8 => 0
50-
let value = value as ffi::BOOL;
39+
// true as BOOL => 1 (YES)
40+
// false as BOOL => 0 (NO)
41+
let value = value as objc_sys::BOOL;
5142
Self { value }
5243
}
5344

5445
/// Creates this from a boolean value received from a raw Objective-C API.
5546
#[inline]
56-
pub const fn from_raw(value: ffi::BOOL) -> Self {
47+
pub const fn from_raw(value: objc_sys::BOOL) -> Self {
5748
Self { value }
5849
}
5950

6051
/// Retrieves the inner [`objc_sys::BOOL`] boolean type, to be used in raw
6152
/// Objective-C APIs.
6253
#[inline]
63-
pub const fn as_raw(self) -> ffi::BOOL {
54+
pub const fn as_raw(self) -> objc_sys::BOOL {
6455
self.value
6556
}
6657

67-
/// Returns `true` if `self` is [`NO`][`Self::NO`].
58+
/// Returns `true` if `self` is [`NO`][Self::NO].
6859
///
69-
/// You should prefer using [`as_bool`][`Self::as_bool`].
60+
/// You should prefer using [`as_bool`][Self::as_bool].
7061
#[inline]
7162
pub const fn is_false(self) -> bool {
72-
// Always compare with 0
73-
// This is what happens with the `!` operator in C.
74-
self.value as u8 == 0
63+
!self.as_bool()
7564
}
7665

77-
/// Returns `true` if `self` is the opposite of [`NO`][`Self::NO`].
66+
/// Returns `true` if `self` is not [`NO`][Self::NO].
7867
///
79-
/// You should prefer using [`as_bool`][`Self::as_bool`].
68+
/// You should prefer using [`as_bool`][Self::as_bool].
8069
#[inline]
8170
pub const fn is_true(self) -> bool {
82-
// Always compare with 0
83-
// This is what happens when using `if` in C.
84-
self.value as u8 != 0
71+
self.as_bool()
8572
}
8673

8774
/// Converts this into the [`bool`] equivalent.
8875
#[inline]
8976
pub const fn as_bool(self) -> bool {
90-
self.is_true()
77+
// Always compare with 0 (NO)
78+
// This is what happens with the `!` operator / when using `if` in C.
79+
self.value != objc_sys::NO
9180
}
9281
}
9382

@@ -113,7 +102,11 @@ impl fmt::Debug for Bool {
113102

114103
// SAFETY: `Bool` is `repr(transparent)`.
115104
unsafe impl Encode for Bool {
116-
const ENCODING: Encoding = ffi::BOOL::ENCODING;
105+
// i8::__ENCODING == Encoding::Char
106+
// u8::__ENCODING == Encoding::UChar
107+
// bool::__ENCODING == Encoding::Bool
108+
// i32::__ENCODING == Encoding::Int
109+
const ENCODING: Encoding = objc_sys::BOOL::__ENCODING;
117110
}
118111

119112
// Note that we shouldn't delegate to `BOOL`'s `ENCODING_REF` since `BOOL` is
@@ -185,14 +178,13 @@ mod tests {
185178
assert_eq!(format!("{:?}", Bool::from(false)), "NO");
186179
}
187180

188-
// Can't really do this test since it won't compile on platforms where
189-
// type BOOL = bool.
190-
//
191-
// #[test]
192-
// fn test_outside_normal() {
193-
// let b = Bool::from_raw(42);
194-
// assert!(b.is_true());
195-
// assert!(!b.is_false());
196-
// assert_eq!(b.as_raw(), 42);
197-
// }
181+
#[test]
182+
// Test on platform where we know the type of BOOL
183+
#[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))]
184+
fn test_outside_normal() {
185+
let b = Bool::from_raw(42);
186+
assert!(b.is_true());
187+
assert!(!b.is_false());
188+
assert_eq!(b.as_raw(), 42);
189+
}
198190
}

0 commit comments

Comments
 (0)