objc2/__macro_helpers/
cache.rs1use core::ffi::{c_char, c_void, CStr};
2use core::ptr;
3use core::str;
4use core::sync::atomic::{AtomicPtr, Ordering};
5
6use crate::ffi;
7use crate::runtime::{AnyClass, Sel};
8
9#[derive(Debug)]
11pub struct CachedSel {
12 ptr: AtomicPtr<c_void>,
13}
14
15impl CachedSel {
16 #[allow(clippy::new_without_default)]
18 pub const fn new() -> Self {
19 Self {
20 ptr: AtomicPtr::new(ptr::null_mut()),
21 }
22 }
23
24 #[cold]
27 unsafe fn fetch(&self, name: *const c_char) -> Sel {
28 let sel = unsafe { Sel::register_unchecked(name) };
35 self.ptr.store(sel.as_ptr() as *mut _, Ordering::Relaxed);
36 sel
37 }
38
39 #[inline]
42 pub unsafe fn get(&self, name: &str) -> Sel {
43 let ptr = self.ptr.load(Ordering::Relaxed);
45 if let Some(sel) = unsafe { Sel::from_ptr(ptr) } {
46 sel
47 } else {
48 unsafe { self.fetch(name.as_ptr().cast()) }
50 }
51 }
52}
53
54#[derive(Debug)]
56pub struct CachedClass {
57 ptr: AtomicPtr<AnyClass>,
58}
59
60impl CachedClass {
61 #[allow(clippy::new_without_default)]
63 pub const fn new() -> CachedClass {
64 CachedClass {
65 ptr: AtomicPtr::new(ptr::null_mut()),
66 }
67 }
68
69 #[cold]
72 #[track_caller]
73 unsafe fn fetch(&self, name: *const c_char) -> &'static AnyClass {
74 let ptr: *const AnyClass = unsafe { ffi::objc_getClass(name) }.cast();
75 self.ptr.store(ptr as *mut AnyClass, Ordering::Relaxed);
76 if let Some(cls) = unsafe { ptr.as_ref() } {
77 cls
78 } else {
79 let name = unsafe { CStr::from_ptr(name) };
83 let name = str::from_utf8(name.to_bytes()).unwrap();
84 panic!("class {name} could not be found")
85 }
86 }
87
88 #[inline]
91 #[track_caller]
92 pub unsafe fn get(&self, name: &str) -> &'static AnyClass {
93 let ptr = self.ptr.load(Ordering::Relaxed);
95 if let Some(cls) = unsafe { ptr.as_ref() } {
96 cls
97 } else {
98 unsafe { self.fetch(name.as_ptr().cast()) }
100 }
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 #[test]
107 #[should_panic = "class NonExistentClass could not be found"]
108 #[cfg(not(feature = "unstable-static-class"))]
109 fn test_not_found() {
110 let _ = crate::class!(NonExistentClass);
111 }
112}