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() { None } else { Some(Self(ptr)) }
38 }
39
40 #[must_use]
47 pub unsafe fn from_raw_borrowed(ptr: *mut c_void) -> Option<Self> {
48 if ptr.is_null() {
49 None
50 } else {
51 let retained = unsafe { ffi::cf_type_retain(ptr) };
52 unsafe { Self::from_raw(retained) }
53 }
54 }
55
56 #[must_use]
58 pub const fn as_ptr(&self) -> *mut c_void {
59 self.0
60 }
61
62 #[must_use]
64 pub fn type_id(&self) -> usize {
65 unsafe { ffi::cf_type_get_type_id(self.0) }
66 }
67
68 #[must_use]
69 pub fn as_number(&self) -> Option<crate::cf::CFNumber> {
70 (self.type_id() == crate::cf::CFNumber::type_id())
71 .then(|| unsafe { crate::cf::CFNumber::from_raw_borrowed(self.0) })
72 .flatten()
73 }
74
75 #[must_use]
77 pub fn hash_code(&self) -> usize {
78 unsafe { ffi::cf_type_hash(self.0) }
79 }
80
81 #[must_use]
83 pub fn description(&self) -> String {
84 if self.type_id() == unsafe { ffi::cf_run_loop_get_type_id() } {
85 return format!("<CFRunLoop {:p}>", self.0);
86 }
87 let ptr = unsafe { ffi::acf_cf_type_copy_description_string(self.0) };
88 unsafe { crate::cf::CFString::from_raw(ptr) }
89 .map_or_else(String::new, |description| description.to_string_lossy())
90 }
91}
92
93crate::utils::retained::cf_retained!(
94 CFType,
95 retain = ffi::cf_type_retain,
96 release = ffi::cf_type_release,
97);
98
99unsafe impl AsCFType for CFType {
100 fn as_ptr(&self) -> *mut c_void {
101 self.0
102 }
103}
104
105impl PartialEq for CFType {
106 fn eq(&self, other: &Self) -> bool {
107 unsafe { ffi::cf_type_equal(self.0, other.0) }
108 }
109}
110
111impl Eq for CFType {}
112
113impl std::hash::Hash for CFType {
114 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
115 self.hash_code().hash(state);
116 }
117}
118
119impl fmt::Debug for CFType {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 f.debug_struct("CFType")
122 .field("ptr", &self.0)
123 .field("type_id", &self.type_id())
124 .field("description", &self.description())
125 .finish()
126 }
127}
128
129impl fmt::Display for CFType {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 f.write_str(&self.description())
132 }
133}
134
135pub struct SwiftObject(*mut c_void);
137
138impl SwiftObject {
139 #[must_use]
141 pub(crate) fn from_raw_owned(ptr: *mut c_void) -> Option<Self> {
142 if ptr.is_null() { None } else { Some(Self(ptr)) }
143 }
144
145 #[must_use]
147 pub(crate) const fn as_ptr(&self) -> *mut c_void {
148 self.0
149 }
150}
151
152crate::utils::retained::cf_retained!(
153 SwiftObject,
154 retain = ffi::acf_object_retain,
155 release = ffi::acf_object_release,
156);
157
158impl PartialEq for SwiftObject {
159 fn eq(&self, other: &Self) -> bool {
160 self.0 == other.0
161 }
162}
163
164impl Eq for SwiftObject {}
165
166impl std::hash::Hash for SwiftObject {
167 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
168 unsafe { ffi::acf_object_hash(self.0) }.hash(state);
169 }
170}
171
172impl fmt::Debug for SwiftObject {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 f.debug_struct("SwiftObject").field("ptr", &self.0).finish()
175 }
176}
177
178macro_rules! impl_cf_type_wrapper {
179 ($name:ident, $type_id_fn:ident) => {
180 #[derive(Clone, PartialEq, Eq, Hash)]
181 #[doc = concat!("Safe wrapper around a retained Core Foundation `", stringify!($name), "` reference.")]
182 pub struct $name(pub(crate) crate::cf::base::CFType);
183
184 impl $name {
185 #[doc = concat!("Adopts a +1 retained `", stringify!($name), "` pointer and returns `None` for null.")]
186 #[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.")]
190 #[must_use]
191 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
192 unsafe { crate::cf::base::CFType::from_raw(ptr) }.map(Self)
193 }
194
195 #[doc = concat!("Retains a +0 borrowed `", stringify!($name), "` pointer and returns an owned wrapper.")]
196 #[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.")]
200 #[must_use]
201 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
202 unsafe { crate::cf::base::CFType::from_raw_borrowed(ptr) }.map(Self)
203 }
204
205 #[must_use]
207 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
208 self.0.as_ptr()
209 }
210
211 #[doc = concat!("Returns the Core Foundation type ID for `", stringify!($name), "`.")]
212 #[must_use]
213 pub fn type_id() -> usize {
214 unsafe { crate::ffi::$type_id_fn() }
215 }
216
217 #[must_use]
219 pub fn into_cf_type(self) -> crate::cf::base::CFType {
220 self.0
221 }
222 }
223
224 unsafe impl crate::cf::base::AsCFType for $name {
225 fn as_ptr(&self) -> *mut std::ffi::c_void {
226 self.as_ptr()
227 }
228 }
229
230 impl std::fmt::Debug for $name {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 f.debug_struct(stringify!($name))
233 .field("ptr", &self.as_ptr())
234 .field("description", &self.0.description())
235 .finish()
236 }
237 }
238 };
239}
240
241pub(crate) use impl_cf_type_wrapper;