1use crate::ffi;
2use std::ffi::c_void;
3use std::fmt;
4
5pub unsafe trait AsCFType {
13 fn as_ptr(&self) -> *mut c_void;
15
16 #[must_use]
18 fn to_cf_type(&self) -> CFType {
19 let retained = unsafe { ffi::cf_type_retain(self.as_ptr()) };
20 unsafe { CFType::from_raw(retained) }.expect("retained CFType pointer must be non-null")
21 }
22}
23
24pub struct CFType(*mut c_void);
26
27impl CFType {
28 #[must_use]
36 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
37 if ptr.is_null() {
38 None
39 } else {
40 Some(Self(ptr))
41 }
42 }
43
44 #[must_use]
51 pub unsafe fn from_raw_borrowed(ptr: *mut c_void) -> Option<Self> {
52 if ptr.is_null() {
53 None
54 } else {
55 let retained = unsafe { ffi::cf_type_retain(ptr) };
56 unsafe { Self::from_raw(retained) }
57 }
58 }
59
60 #[must_use]
62 pub const fn as_ptr(&self) -> *mut c_void {
63 self.0
64 }
65
66 #[must_use]
68 pub fn type_id(&self) -> usize {
69 unsafe { ffi::cf_type_get_type_id(self.0) }
70 }
71
72 #[must_use]
74 pub fn hash_code(&self) -> usize {
75 unsafe { ffi::cf_type_hash(self.0) }
76 }
77
78 #[must_use]
80 pub fn description(&self) -> String {
81 if self.type_id() == unsafe { ffi::cf_run_loop_get_type_id() } {
82 return format!("<CFRunLoop {:p}>", self.0);
83 }
84 let ptr = unsafe { ffi::acf_cf_type_copy_description_string(self.0) };
85 unsafe { crate::cf::CFString::from_raw(ptr) }
86 .map_or_else(String::new, |description| description.to_string_lossy())
87 }
88}
89
90crate::utils::retained::cf_retained!(
91 CFType,
92 retain = ffi::cf_type_retain,
93 release = ffi::cf_type_release,
94);
95
96unsafe impl AsCFType for CFType {
97 fn as_ptr(&self) -> *mut c_void {
98 self.0
99 }
100}
101
102impl PartialEq for CFType {
103 fn eq(&self, other: &Self) -> bool {
104 unsafe { ffi::cf_type_equal(self.0, other.0) }
105 }
106}
107
108impl Eq for CFType {}
109
110impl std::hash::Hash for CFType {
111 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
112 self.hash_code().hash(state);
113 }
114}
115
116impl fmt::Debug for CFType {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 f.debug_struct("CFType")
119 .field("ptr", &self.0)
120 .field("type_id", &self.type_id())
121 .field("description", &self.description())
122 .finish()
123 }
124}
125
126impl fmt::Display for CFType {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.write_str(&self.description())
129 }
130}
131
132pub struct SwiftObject(*mut c_void);
134
135impl SwiftObject {
136 #[must_use]
138 pub(crate) fn from_raw_owned(ptr: *mut c_void) -> Option<Self> {
139 if ptr.is_null() {
140 None
141 } else {
142 Some(Self(ptr))
143 }
144 }
145
146 #[must_use]
148 pub(crate) const fn as_ptr(&self) -> *mut c_void {
149 self.0
150 }
151}
152
153crate::utils::retained::cf_retained!(
154 SwiftObject,
155 retain = ffi::acf_object_retain,
156 release = ffi::acf_object_release,
157);
158
159impl PartialEq for SwiftObject {
160 fn eq(&self, other: &Self) -> bool {
161 self.0 == other.0
162 }
163}
164
165impl Eq for SwiftObject {}
166
167impl std::hash::Hash for SwiftObject {
168 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
169 unsafe { ffi::acf_object_hash(self.0) }.hash(state);
170 }
171}
172
173impl fmt::Debug for SwiftObject {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 f.debug_struct("SwiftObject").field("ptr", &self.0).finish()
176 }
177}
178
179macro_rules! impl_cf_type_wrapper {
180 ($name:ident, $type_id_fn:ident) => {
181 #[derive(Clone, PartialEq, Eq, Hash)]
182 #[doc = concat!("Safe wrapper around a retained Core Foundation `", stringify!($name), "` reference.")]
183 pub struct $name(pub(crate) crate::cf::base::CFType);
184
185 impl $name {
186 #[doc = concat!("Adopts a +1 retained `", stringify!($name), "` pointer and returns `None` for null.")]
187 #[doc = concat!("A non-null `ptr` must be a live `", stringify!($name), "` pointer of the exact dynamic type carrying one retain transferred to this wrapper. The caller must not release or separately adopt that transferred retain.")]
191 #[must_use]
192 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
193 unsafe { crate::cf::base::CFType::from_raw(ptr) }.map(Self)
194 }
195
196 #[doc = concat!("Retains a +0 borrowed `", stringify!($name), "` pointer and returns an owned wrapper.")]
197 #[doc = concat!("A non-null `ptr` must be a live `", stringify!($name), "` pointer of the exact dynamic type for the duration of the retain call.")]
201 #[must_use]
202 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
203 unsafe { crate::cf::base::CFType::from_raw_borrowed(ptr) }.map(Self)
204 }
205
206 #[must_use]
208 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
209 self.0.as_ptr()
210 }
211
212 #[doc = concat!("Returns the Core Foundation type ID for `", stringify!($name), "`.")]
213 #[must_use]
214 pub fn type_id() -> usize {
215 unsafe { crate::ffi::$type_id_fn() }
216 }
217
218 #[must_use]
220 pub fn into_cf_type(self) -> crate::cf::base::CFType {
221 self.0
222 }
223 }
224
225 unsafe impl crate::cf::base::AsCFType for $name {
226 fn as_ptr(&self) -> *mut std::ffi::c_void {
227 self.as_ptr()
228 }
229 }
230
231 impl std::fmt::Debug for $name {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 f.debug_struct(stringify!($name))
234 .field("ptr", &self.as_ptr())
235 .field("description", &self.0.description())
236 .finish()
237 }
238 }
239 };
240}
241
242pub(crate) use impl_cf_type_wrapper;