Skip to main content

mtl_foundation/
notification.rs

1//! Notification types for Foundation.
2//!
3//! Corresponds to `Foundation/NSNotification.hpp`.
4//!
5//! # C++ Equivalent
6//!
7//! ```cpp
8//! namespace NS {
9//! using NotificationName = class String*;
10//!
11//! class Notification : public NS::Referencing<Notification> {
12//! public:
13//!     NS::String*     name() const;
14//!     NS::Object*     object() const;
15//!     NS::Dictionary* userInfo() const;
16//! };
17//!
18//! class NotificationCenter : public NS::Referencing<NotificationCenter> {
19//! public:
20//!     static class NotificationCenter* defaultCenter();
21//!     Object* addObserver(NotificationName name, Object* pObj, void* pQueue, ObserverBlock block);
22//!     void removeObserver(Object* pObserver);
23//! };
24//! }
25//! ```
26
27use std::ffi::c_void;
28use std::ptr::NonNull;
29
30use mtl_sys::{class, msg_send_0, msg_send_1, sel};
31
32use crate::dictionary::Dictionary;
33use crate::object::{Object, Referencing};
34use crate::string::String;
35
36/// Notification name type (alias for String pointer).
37///
38/// C++ equivalent: `NS::NotificationName`
39pub type NotificationName = *mut String;
40
41/// An Objective-C notification object.
42///
43/// C++ equivalent: `NS::Notification`
44#[repr(transparent)]
45#[derive(Clone)]
46pub struct Notification(NonNull<c_void>);
47
48impl Notification {
49    /// Get the notification name.
50    ///
51    /// C++ equivalent: `NS::String* name() const`
52    #[inline]
53    pub fn name(&self) -> *mut String {
54        unsafe { msg_send_0(self.as_ptr(), sel!(name)) }
55    }
56
57    /// Get the notification object.
58    ///
59    /// C++ equivalent: `NS::Object* object() const`
60    #[inline]
61    pub fn object(&self) -> *mut Object {
62        unsafe { msg_send_0(self.as_ptr(), sel!(object)) }
63    }
64
65    /// Get the notification user info dictionary.
66    ///
67    /// C++ equivalent: `NS::Dictionary* userInfo() const`
68    #[inline]
69    pub fn user_info(&self) -> *mut Dictionary {
70        unsafe { msg_send_0(self.as_ptr(), sel!(userInfo)) }
71    }
72
73    /// Create a Notification from a raw pointer.
74    ///
75    /// # Safety
76    ///
77    /// The pointer must be a valid Objective-C NSNotification object.
78    #[inline]
79    pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
80        NonNull::new(ptr).map(Self)
81    }
82}
83
84impl Referencing for Notification {
85    #[inline]
86    fn as_ptr(&self) -> *const c_void {
87        self.0.as_ptr()
88    }
89}
90
91unsafe impl Send for Notification {}
92unsafe impl Sync for Notification {}
93
94impl std::fmt::Debug for Notification {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        f.debug_struct("Notification")
97            .field("ptr", &self.0)
98            .finish()
99    }
100}
101
102/// An Objective-C notification center.
103///
104/// C++ equivalent: `NS::NotificationCenter`
105#[repr(transparent)]
106#[derive(Clone)]
107pub struct NotificationCenter(NonNull<c_void>);
108
109impl NotificationCenter {
110    /// Get the default notification center.
111    ///
112    /// C++ equivalent: `static class NotificationCenter* defaultCenter()`
113    #[inline]
114    pub fn default_center() -> Option<Self> {
115        unsafe {
116            let ptr: *mut c_void =
117                msg_send_0(class!(NSNotificationCenter).as_ptr(), sel!(defaultCenter));
118            Self::from_ptr(ptr)
119        }
120    }
121
122    /// Add an observer with a block.
123    ///
124    /// C++ equivalent: `Object* addObserver(NotificationName name, Object* pObj, void* pQueue, ObserverBlock block)`
125    ///
126    /// Note: The block parameter is a raw pointer to an Objective-C block.
127    /// Use with mtl_sys block types.
128    #[inline]
129    pub fn add_observer(
130        &self,
131        name: NotificationName,
132        object: *mut Object,
133        queue: *mut c_void,
134        block: *const c_void,
135    ) -> *mut Object {
136        unsafe {
137            mtl_sys::msg_send_4(
138                self.as_ptr(),
139                sel!(addObserverForName:object:queue:usingBlock:),
140                name,
141                object,
142                queue,
143                block,
144            )
145        }
146    }
147
148    /// Remove an observer.
149    ///
150    /// C++ equivalent: `void removeObserver(Object* pObserver)`
151    #[inline]
152    pub fn remove_observer(&self, observer: &Object) {
153        unsafe {
154            let _: () = msg_send_1(self.as_ptr(), sel!(removeObserver:), observer.as_ptr());
155        }
156    }
157
158    /// Create a NotificationCenter from a raw pointer.
159    ///
160    /// # Safety
161    ///
162    /// The pointer must be a valid Objective-C NSNotificationCenter object.
163    #[inline]
164    pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
165        NonNull::new(ptr).map(Self)
166    }
167}
168
169impl Referencing for NotificationCenter {
170    #[inline]
171    fn as_ptr(&self) -> *const c_void {
172        self.0.as_ptr()
173    }
174}
175
176unsafe impl Send for NotificationCenter {}
177unsafe impl Sync for NotificationCenter {}
178
179impl std::fmt::Debug for NotificationCenter {
180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181        f.debug_struct("NotificationCenter")
182            .field("ptr", &self.0)
183            .finish()
184    }
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190
191    #[test]
192    fn test_notification_size() {
193        assert_eq!(
194            std::mem::size_of::<Notification>(),
195            std::mem::size_of::<*mut c_void>()
196        );
197    }
198
199    #[test]
200    fn test_notification_center_size() {
201        assert_eq!(
202            std::mem::size_of::<NotificationCenter>(),
203            std::mem::size_of::<*mut c_void>()
204        );
205    }
206}