Skip to content

Commit

Permalink
Merge pull request #286 from madsmtm/cfg-in-declare-class
Browse files Browse the repository at this point in the history
Handle `cfg` in `declare class!`
  • Loading branch information
madsmtm authored Nov 9, 2022
2 parents 2063dee + 0a7cd46 commit 26ec63e
Show file tree
Hide file tree
Showing 11 changed files with 654 additions and 297 deletions.
2 changes: 2 additions & 0 deletions objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Fixed
* Fixed duplicate selector extraction in `extern_methods!`.
* Fixed using `deprecated` attributes in `declare_class!`.
* Fixed `cfg` attributes on methods and implementations in `declare_class!`.


## 0.3.0-beta.3 - 2022-09-01
Expand Down
2 changes: 2 additions & 0 deletions objc2/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@
//! assert_eq!(n, 12);
//! ```
#[cfg(test)]
mod declare_class_tests;
mod ivar;
mod ivar_drop;
mod ivar_forwarding_impls;
Expand Down
175 changes: 175 additions & 0 deletions objc2/src/declare/declare_class_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#![deny(deprecated)]
use crate::foundation::NSObject;
use crate::rc::{Id, Owned};
use crate::{declare_class, extern_methods, sel, ClassType};

// Test that adding the `deprecated` attribute does not mean that warnings
// when using the method internally are output.
declare_class!(
struct DeclareClassDepreactedMethod {}

unsafe impl ClassType for DeclareClassDepreactedMethod {
type Super = NSObject;
}

#[deprecated]
unsafe impl DeclareClassDepreactedMethod {
#[method(deprecatedOnImpl)]
fn deprecated_on_impl() {}
}

unsafe impl DeclareClassDepreactedMethod {
#[deprecated]
#[method(deprecatedOnMethod)]
fn deprecated_on_method() {}
}
);

#[test]
fn test_deprecated() {
let _cls = DeclareClassDepreactedMethod::class();
}

// Test that `cfg` works properly.
//
// We use `debug_assertions` here just because it's something that we know
// our CI already tests.
declare_class!(
struct DeclareClassCfg {}

unsafe impl ClassType for DeclareClassCfg {
type Super = NSObject;
}

unsafe impl DeclareClassCfg {
#[cfg(debug_assertions)]
#[method(changesOnCfg1)]
fn _changes_on_cfg1() -> i32 {
1
}

#[cfg(not(debug_assertions))]
#[method(changesOnCfg1)]
fn _changes_on_cfg1() -> i32 {
2
}

#[cfg(debug_assertions)]
#[method(onlyWhenEnabled1)]
fn _only_when_enabled1(&self) {}

#[cfg(not(debug_assertions))]
#[method(onlyWhenDisabled1)]
fn _only_when_disabled1(&self) {}
}

#[cfg(debug_assertions)]
unsafe impl DeclareClassCfg {
#[method(changesOnCfg2)]
fn _changes_on_cfg2(&self) -> i32 {
1
}

#[method(onlyWhenEnabled2)]
fn _only_when_enabled2() {}
}

#[cfg(not(debug_assertions))]
unsafe impl DeclareClassCfg {
#[method(changesOnCfg2)]
fn _changes_on_cfg2(&self) -> i32 {
2
}

#[method(onlyWhenDisabled2)]
fn _only_when_disabled2() {}
}

#[cfg(debug_assertions)]
unsafe impl DeclareClassCfg {
#[cfg(not(debug_assertions))]
#[method(never)]
fn _never(&self) {}

#[cfg(not(debug_assertions))]
#[method(never)]
fn _never_class() {}
}
);

extern_methods!(
unsafe impl DeclareClassCfg {
#[method_id(new)]
fn new() -> Id<Self, Owned>;
}

unsafe impl DeclareClassCfg {
#[method(changesOnCfg1)]
fn changes_on_cfg1() -> i32;

#[method(changesOnCfg2)]
fn changes_on_cfg2(&self) -> i32;

#[cfg(debug_assertions)]
#[method(onlyWhenEnabled1)]
fn only_when_enabled1(&self);

#[cfg(not(debug_assertions))]
#[method(onlyWhenDisabled1)]
fn only_when_disabled1(&self);
}

#[cfg(debug_assertions)]
unsafe impl DeclareClassCfg {
#[method(onlyWhenEnabled2)]
fn only_when_enabled2();
}

#[cfg(not(debug_assertions))]
unsafe impl DeclareClassCfg {
#[method(onlyWhenDisabled2)]
fn only_when_disabled2();
}
);

#[test]
fn test_method_that_changes_based_on_cfg() {
let expected = if cfg!(debug_assertions) { 1 } else { 2 };
let actual = DeclareClassCfg::changes_on_cfg1();
assert_eq!(expected, actual, "changes_on_cfg1");

let actual = DeclareClassCfg::new().changes_on_cfg2();
assert_eq!(expected, actual, "changes_on_cfg2");
}

#[test]
fn test_method_that_is_only_available_based_on_cfg() {
let cls = DeclareClassCfg::class();
let metacls = cls.metaclass();
let obj = DeclareClassCfg::new();

#[cfg(debug_assertions)]
{
assert!(!cls.responds_to(sel!(onlyWhenDisabled1)));
assert!(!metacls.responds_to(sel!(onlyWhenDisabled2)));

obj.only_when_enabled1();
DeclareClassCfg::only_when_enabled2();
}
#[cfg(not(debug_assertions))]
{
assert!(!cls.responds_to(sel!(onlyWhenEnabled1)));
assert!(!metacls.responds_to(sel!(onlyWhenEnabled2)));

obj.only_when_disabled1();
DeclareClassCfg::only_when_disabled2();
}
}

#[test]
fn test_method_that_is_never_available() {
let cls = DeclareClassCfg::class();
let metacls = cls.metaclass();
assert!(!cls.responds_to(sel!(never)));
assert!(!metacls.responds_to(sel!(never)));
}
1 change: 1 addition & 0 deletions objc2/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod __attribute_helpers;
mod __msg_send_parse;
mod __rewrite_self_arg;
mod declare_class;
Expand Down
Loading

0 comments on commit 26ec63e

Please sign in to comment.