objective_rust/
lib.rs

1pub use objective_rust_macros::*;
2
3#[cfg(not(target_os = "macos"))]
4compile_error!("objective-rust only supports macOS");
5
6/// Objective-C's boolean type.
7#[repr(transparent)]
8pub struct ObjcBool(std::ffi::c_char);
9impl ObjcBool {
10    pub const TRUE: Self = Self(1);
11    pub const FALSE: Self = Self(0);
12
13    pub const YES: Self = Self::TRUE;
14    pub const NO: Self = Self::FALSE;
15}
16impl From<bool> for ObjcBool {
17    fn from(value: bool) -> Self {
18        match value {
19            true => Self::TRUE,
20            false => Self::FALSE,
21        }
22    }
23}
24impl From<ObjcBool> for bool {
25    fn from(value: ObjcBool) -> bool {
26        match value.0 {
27            1 => true,
28            0 => false,
29            _ => unreachable!(),
30        }
31    }
32}
33
34pub mod ffi {
35    use std::{ffi::CString, ptr::NonNull};
36    type Ptr = NonNull<()>;
37
38    /// An Objective-C class.
39    #[repr(transparent)]
40    #[derive(Clone, Copy)]
41    pub struct Class(Ptr);
42    /// An instance of an Objective-C class.
43    #[repr(transparent)]
44    #[derive(Clone, Copy)]
45    pub struct Instance(Ptr);
46    /// A pointer to the implementation of an Objective-C function.
47    #[repr(transparent)]
48    #[derive(Clone, Copy)]
49    pub struct Implementation(Ptr);
50    /// A selector for an Objective-C function.
51    #[repr(transparent)]
52    #[derive(Clone, Copy)]
53    pub struct Selector(Ptr);
54    /// A structure that defines an Objective-C method.
55    #[repr(transparent)]
56    #[derive(Clone, Copy)]
57    pub struct Method(Ptr);
58
59    /// Returns a [`Class`] if one exists for `name`. Otherwise returns `None`.
60    ///
61    /// https://developer.apple.com/documentation/objectivec/1418952-objc_getclass?language=objc
62    pub fn get_class(name: &str) -> Option<Class> {
63        let name = CString::new(name).ok()?;
64        let ptr = unsafe { objc_getClass(name.as_ptr()) };
65
66        Some(Class(Ptr::new(ptr)?))
67    }
68
69    pub fn get_metaclass(name: &str) -> Option<Class> {
70        let name = CString::new(name).ok()?;
71        let ptr = unsafe { objc_getMetaClass(name.as_ptr()) };
72
73        Some(Class(Ptr::new(ptr)?))
74    }
75
76    pub fn get_selector(name: &str) -> Option<Selector> {
77        let name = CString::new(name).ok()?;
78        let ptr = unsafe { sel_getUid(name.as_ptr()) };
79
80        Some(Selector(Ptr::new(ptr)?))
81    }
82
83    #[inline(always)]
84    pub fn get_method_impl(class: Class, method: Selector) -> Option<Implementation> {
85        let ptr = unsafe { class_getMethodImplementation(class, method) };
86        Some(Implementation(Ptr::new(ptr)?))
87    }
88
89    #[link(name = "objc")]
90    extern "C" {
91        fn class_getMethodImplementation(cls: Class, name: Selector) -> *mut ();
92        fn objc_getClass(name: *const i8) -> *mut ();
93        fn objc_getMetaClass(name: *const i8) -> *mut ();
94        fn sel_getUid(name: *const i8) -> *mut ();
95    }
96}