Skip to content

Commit e32b072

Browse files
authored
Merge pull request #492 from madsmtm/icrate-documentation-examples
Improve documentation
2 parents 7f0b60e + d094b59 commit e32b072

File tree

10 files changed

+149
-87
lines changed

10 files changed

+149
-87
lines changed

crates/icrate/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,9 @@ unstable-example-delegate = [
132132
"apple",
133133
"Foundation",
134134
"Foundation_NSString",
135+
"Foundation_NSNotification",
135136
"AppKit",
136-
"AppKit_NSResponder",
137+
"AppKit_NSApplication",
137138
]
138139
unstable-example-speech_synthesis = [
139140
"apple",

crates/icrate/README.md

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55
[![Documentation](https://docs.rs/icrate/badge.svg)](https://docs.rs/icrate/)
66
[![CI](https://github.com/madsmtm/objc2/actions/workflows/ci.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/ci.yml)
77

8-
Rust bindings to Apple's frameworks..
8+
Rust bindings to Apple's frameworks.
99

10-
This crate is part of the [`objc2` project](https://github.com/madsmtm/objc2),
11-
see that for related crates, or see [the docs](https://docs.rs/icrate/) for
12-
more details.
10+
This README is kept intentionally small in an effort to consolidate the documentation, see [the Rust docs](https://docs.rs/icrate/) for more details.
1311

1412

1513
## Supported versions
@@ -22,20 +20,3 @@ Currently supports:
2220
- iOS/iPadOS: `7.0-16.2` (WIP)
2321
- tvOS: `9.0-16.1` (WIP)
2422
- watchOS: `1.0-9.1` (WIP)
25-
26-
27-
## Example
28-
29-
```rust
30-
use icrate::Foundation::{ns_string, NSCopying, NSArray};
31-
32-
let string = ns_string!("world");
33-
println!("hello {string}");
34-
35-
let array = NSArray::from_id_slice(&[string.copy()]);
36-
println!("{array:?}");
37-
```
38-
39-
More examples are [available in the repository][examples].
40-
41-
[examples]: https://github.com/madsmtm/objc2/tree/master/crates/icrate/examples

crates/icrate/examples/browser.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
#![deny(unsafe_op_in_unsafe_fn)]
2-
#![cfg_attr(not(target_os = "macos"), allow(unused))]
3-
42
use core::{cell::RefCell, ptr::NonNull};
53

64
use icrate::{

crates/icrate/examples/delegate.rs

Lines changed: 34 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
#![deny(unsafe_op_in_unsafe_fn)]
2-
#![cfg_attr(not(target_os = "macos"), allow(unused))]
32
use std::ptr::NonNull;
43

5-
use icrate::Foundation::{ns_string, NSCopying, NSObject, NSString};
4+
use icrate::AppKit::{NSApplication, NSApplicationActivationPolicyRegular, NSApplicationDelegate};
5+
use icrate::Foundation::{
6+
ns_string, NSCopying, NSNotification, NSObject, NSObjectProtocol, NSString,
7+
};
68
use objc2::declare::{Ivar, IvarBool, IvarDrop, IvarEncode};
79
use objc2::rc::Id;
8-
use objc2::runtime::AnyObject;
10+
use objc2::runtime::ProtocolObject;
911
use objc2::{declare_class, msg_send, msg_send_id, mutability, ClassType};
1012

11-
#[cfg(target_os = "macos")]
12-
#[link(name = "AppKit", kind = "framework")]
13-
extern "C" {}
14-
15-
#[cfg(target_os = "macos")]
1613
declare_class!(
1714
#[derive(Debug)]
18-
struct CustomAppDelegate {
19-
pub ivar: IvarEncode<u8, "_ivar">,
15+
struct AppDelegate {
16+
ivar: IvarEncode<u8, "_ivar">,
2017
another_ivar: IvarBool<"_another_ivar">,
2118
box_ivar: IvarDrop<Box<i32>, "_box_ivar">,
2219
maybe_box_ivar: IvarDrop<Option<Box<i32>>, "_maybe_box_ivar">,
@@ -26,14 +23,14 @@ declare_class!(
2623

2724
mod ivars;
2825

29-
unsafe impl ClassType for CustomAppDelegate {
26+
unsafe impl ClassType for AppDelegate {
3027
#[inherits(NSObject)]
3128
type Super = icrate::AppKit::NSResponder;
3229
type Mutability = mutability::InteriorMutable;
33-
const NAME: &'static str = "MyCustomAppDelegate";
30+
const NAME: &'static str = "MyAppDelegate";
3431
}
3532

36-
unsafe impl CustomAppDelegate {
33+
unsafe impl AppDelegate {
3734
#[method(initWith:another:)]
3835
unsafe fn init_with(
3936
this: *mut Self,
@@ -42,70 +39,56 @@ declare_class!(
4239
) -> Option<NonNull<Self>> {
4340
let this: Option<&mut Self> = unsafe { msg_send![super(this), init] };
4441

45-
// TODO: `ns_string` can't be used inside closures; investigate!
46-
let s = ns_string!("def");
47-
4842
this.map(|this| {
4943
Ivar::write(&mut this.ivar, ivar);
50-
*this.another_ivar = another_ivar;
51-
*this.maybe_box_ivar = None;
52-
*this.maybe_id_ivar = Some(s.copy());
44+
Ivar::write(&mut this.another_ivar, another_ivar);
45+
Ivar::write(&mut this.maybe_box_ivar, None);
46+
Ivar::write(&mut this.maybe_id_ivar, Some(ns_string!("def").copy()));
5347
Ivar::write(&mut this.box_ivar, Box::new(2));
5448
Ivar::write(&mut this.id_ivar, NSString::from_str("abc"));
5549
NonNull::from(this)
5650
})
5751
}
58-
59-
#[method(myClassMethod)]
60-
fn my_class_method() {
61-
println!("A class method!");
62-
}
6352
}
6453

65-
// For some reason, `NSApplicationDelegate` is not a "real" protocol we
66-
// can retrieve using `objc_getProtocol` - it seems it is created by
67-
// `clang` only when used in Objective-C...
68-
//
69-
// TODO: Investigate this!
70-
unsafe impl CustomAppDelegate {
71-
/// This is `unsafe` because it expects `sender` to be valid
54+
unsafe impl NSApplicationDelegate for AppDelegate {
7255
#[method(applicationDidFinishLaunching:)]
73-
unsafe fn did_finish_launching(&self, sender: *mut AnyObject) {
56+
fn did_finish_launching(&self, notification: &NSNotification) {
7457
println!("Did finish launching!");
75-
// Do something with `sender`
76-
dbg!(sender);
58+
// Do something with the notification
59+
dbg!(notification);
7760
}
7861

79-
/// Some comment before `sel`.
8062
#[method(applicationWillTerminate:)]
81-
/// Some comment after `sel`.
82-
fn will_terminate(&self, _: *mut AnyObject) {
63+
fn will_terminate(&self, _notification: &NSNotification) {
8364
println!("Will terminate!");
8465
}
8566
}
8667
);
8768

88-
#[cfg(target_os = "macos")]
89-
impl CustomAppDelegate {
69+
unsafe impl NSObjectProtocol for AppDelegate {}
70+
71+
impl AppDelegate {
9072
pub fn new(ivar: u8, another_ivar: bool) -> Id<Self> {
9173
unsafe { msg_send_id![Self::alloc(), initWith: ivar, another: another_ivar] }
9274
}
9375
}
9476

95-
#[cfg(target_os = "macos")]
9677
fn main() {
97-
let delegate = CustomAppDelegate::new(42, true);
78+
let app = unsafe { NSApplication::sharedApplication() };
79+
unsafe { app.setActivationPolicy(NSApplicationActivationPolicyRegular) };
80+
81+
// initialize the delegate
82+
let delegate = AppDelegate::new(42, true);
9883

9984
println!("{delegate:?}");
100-
println!("{:?}", delegate.ivar);
101-
println!("{:?}", delegate.another_ivar);
102-
println!("{:?}", delegate.box_ivar);
103-
println!("{:?}", delegate.maybe_box_ivar);
104-
println!("{:?}", delegate.id_ivar);
105-
println!("{:?}", delegate.maybe_id_ivar);
106-
}
10785

108-
#[cfg(not(target_os = "macos"))]
109-
fn main() {
110-
panic!("This example uses AppKit, which is only present on macOS");
86+
// configure the application delegate
87+
unsafe {
88+
let object = ProtocolObject::from_ref(&*delegate);
89+
app.setDelegate(Some(object));
90+
};
91+
92+
// run the app
93+
unsafe { app.run() };
11194
}

crates/icrate/src/AppKit/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
//! # Bindings to the `AppKit` framework
2+
//!
3+
//!
4+
//! ## Examples
5+
//!
6+
//! Implementing `NSApplicationDelegate` for a custom class.
7+
//!
8+
//! ```ignore
9+
#![doc = include_str!("../../examples/delegate.rs")]
10+
//! ```
11+
//!
12+
//! An example showing basic and a bit more advanced usage of `NSPasteboard`.
13+
//!
14+
//! ```ignore
15+
#![doc = include_str!("../../examples/nspasteboard.rs")]
16+
//! ```
17+
118
mod fixes;
219
#[path = "../generated/AppKit/mod.rs"]
320
mod generated;

crates/icrate/src/Foundation/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,21 @@
7373
//! | `NSMutableDictionary<K, V>*` | `HashMap<K, V>` |
7474
//! | `NSEnumerator<T>*` | `Box<dyn Iterator<T>>` |
7575
//! | `NSCopying*` | `Box<dyn Clone>` |
76+
//!
77+
//!
78+
//! ## Examples
79+
//!
80+
//! Basic usage of a few Foundation types.
81+
//!
82+
//! ```ignore
83+
#![doc = include_str!("../../examples/basic_usage.rs")]
84+
//! ```
85+
//!
86+
//! An example showing how to define your own interfaces to parts that may be missing in `icrate`.
87+
//!
88+
//! ```ignore
89+
#![doc = include_str!("../../examples/speech_synthesis.rs")]
90+
//! ```
7691
#![allow(unused_imports)]
7792

7893
#[doc(hidden)]

crates/icrate/src/Metal/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
//! # Bindings to the `Metal` framework
2+
//!
3+
//!
4+
//! ## Examples
5+
//!
6+
//! Drawing a rotating triangle.
7+
//!
8+
//! ```ignore
9+
#![doc = include_str!("../../examples/metal.rs")]
10+
//! ```
111
#![allow(unused_imports)]
212

313
mod capture;

crates/icrate/src/WebKit/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
//! # Bindings to the `WebKit` framework
2+
//!
3+
//!
4+
//! ## Examples
5+
//!
6+
//! ```ignore
7+
#![doc = include_str!("../../examples/browser.rs")]
8+
//! ```
19
mod fixes;
210
#[path = "../generated/WebKit/mod.rs"]
311
mod generated;

crates/icrate/src/lib.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,47 @@
11
//! # Bindings to Apple's frameworks
22
//!
3-
//! This crate is a mostly autogenerated interface to some of Apple's
4-
//! frameworks. It builds upon [`objc2`] to provide memory management and
5-
//! safety in many areas; see that crate for more details.
3+
//! `icrate` is an autogenerated interface to Apple's Objective-C frameworks
4+
//! like AppKit, Foundation, Metal, WebKit, and so on.
5+
//!
6+
//! The bindings currently contain very little documentation, you should view
7+
//! [Apple's developer documentation][apple-doc-index] for detailed
8+
//! information about each API. (There are [plans][#309] for importing that
9+
//! documentation here).
10+
//!
11+
//! [#309]: https://github.com/madsmtm/objc2/issues/309
12+
//! [apple-doc-index]: https://developer.apple.com/documentation/technologies
13+
//!
14+
//!
15+
//! ## Example
16+
//!
17+
//! ```console
18+
//! $ cargo add icrate --features=Foundation,Foundation_all
19+
//! ```
20+
//!
21+
#![cfg_attr(
22+
all(
23+
feature = "Foundation",
24+
feature = "Foundation_NSArray",
25+
feature = "Foundation_NSString"
26+
),
27+
doc = "```"
28+
)]
29+
#![cfg_attr(
30+
not(all(
31+
feature = "Foundation",
32+
feature = "Foundation_NSArray",
33+
feature = "Foundation_NSString"
34+
)),
35+
doc = "```ignore"
36+
)]
37+
//! use icrate::Foundation::{ns_string, NSCopying, NSArray};
38+
//!
39+
//! let string = ns_string!("world");
40+
//! println!("hello {string}");
41+
//!
42+
//! let array = NSArray::from_id_slice(&[string.copy()]);
43+
//! println!("{array:?}");
44+
//! ```
645
746
#![no_std]
847
#![cfg_attr(feature = "unstable-docsrs", feature(doc_auto_cfg))]
@@ -34,11 +73,6 @@ extern crate std;
3473

3574
#[cfg(doctest)]
3675
#[doc = include_str!("../README.md")]
37-
#[cfg(all(
38-
feature = "Foundation",
39-
feature = "Foundation_NSString",
40-
feature = "Foundation_NSArray"
41-
))]
4276
extern "C" {}
4377

4478
#[cfg(feature = "objective-c")]

crates/objc2/src/mutability.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ pub struct Mutable {
104104
/// The mutable counterpart must be specified as the type parameter `MS` to
105105
/// allow `NSCopying` and `NSMutableCopying` to return the correct type.
106106
///
107+
/// Functionality that is provided with this:
108+
/// - [`IsIdCloneable`].
109+
/// - [`IsAllocableAnyThread`].
110+
/// - You are allowed to hand out pointers / references to an instance's
111+
/// internal data, since you know such data will never be mutated.
112+
///
107113
///
108114
/// # Example
109115
///
@@ -259,7 +265,11 @@ impl<IS: ?Sized> Mutability for MutableWithImmutableSuperclass<IS> {}
259265
impl Mutability for InteriorMutable {}
260266
impl Mutability for MainThreadOnly {}
261267

262-
/// Marker trait for classes where [`Id::clone`][clone-id] is safe.
268+
/// Marker trait for classes where [`Id::clone`] is safe.
269+
///
270+
/// Since the `Foundation` collection types (`NSArray<T>`,
271+
/// `NSDictionary<K, V>`, ...) act as if they store [`Id`]s, this also makes
272+
/// certain functionality on those types possible.
263273
///
264274
/// This is implemented for classes whose [`ClassType::Mutability`] is one of:
265275
/// - [`Root`].
@@ -268,19 +278,24 @@ impl Mutability for MainThreadOnly {}
268278
/// - [`InteriorMutable`].
269279
/// - [`MainThreadOnly`].
270280
///
271-
/// [clone-id]: crate::rc::Id#impl-Clone-for-Id<T>
281+
/// [`Id`]: crate::rc::Id
282+
/// [`Id::clone`]: crate::rc::Id#impl-Clone-for-Id<T>
272283
pub trait IsIdCloneable: ClassType {}
273284
impl<T: ?Sized + ClassType> IsIdCloneable for T where T::Mutability: private::MutabilityIsIdCloneable
274285
{}
275286

276-
/// Marker trait for classes where the [`retain`] selector is always safe.
287+
/// Marker trait for classes where the `retain` selector is always safe.
288+
///
289+
/// [`Id::clone`] takes `&Id<T>`, while [`ClassType::retain`] only takes `&T`;
290+
/// the difference between these two is that in the former case, you know that
291+
/// there are no live mutable subclasses.
277292
///
278293
/// This is implemented for classes whose [`ClassType::Mutability`] is one of:
279294
/// - [`Immutable`].
280295
/// - [`InteriorMutable`].
281296
/// - [`MainThreadOnly`].
282297
///
283-
/// [`retain`]: ClassType::retain
298+
/// [`Id::clone`]: crate::rc::Id#impl-Clone-for-Id<T>
284299
pub trait IsRetainable: IsIdCloneable {}
285300
impl<T: ?Sized + ClassType> IsRetainable for T where T::Mutability: private::MutabilityIsRetainable {}
286301

0 commit comments

Comments
 (0)