1use crate::ffi;
2use std::ffi::{c_void, CStr};
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 let ptr = unsafe { ffi::cf_type_copy_description(self.0) };
82 if ptr.is_null() {
83 return String::new();
84 }
85 let string = unsafe { CStr::from_ptr(ptr) }
86 .to_string_lossy()
87 .into_owned();
88 unsafe { ffi::acf_free_string(ptr) };
89 string
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() {
143 None
144 } else {
145 Some(Self(ptr))
146 }
147 }
148
149 #[must_use]
151 pub(crate) const fn as_ptr(&self) -> *mut c_void {
152 self.0
153 }
154}
155
156crate::utils::retained::cf_retained!(
157 SwiftObject,
158 retain = ffi::acf_object_retain,
159 release = ffi::acf_object_release,
160);
161
162impl PartialEq for SwiftObject {
163 fn eq(&self, other: &Self) -> bool {
164 self.0 == other.0
165 }
166}
167
168impl Eq for SwiftObject {}
169
170impl std::hash::Hash for SwiftObject {
171 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
172 unsafe { ffi::acf_object_hash(self.0) }.hash(state);
173 }
174}
175
176impl fmt::Debug for SwiftObject {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 f.debug_struct("SwiftObject").field("ptr", &self.0).finish()
179 }
180}
181
182macro_rules! impl_cf_type_wrapper {
183 ($name:ident, $type_id_fn:ident) => {
184 #[derive(Clone, PartialEq, Eq, Hash)]
185 #[doc = concat!("Safe wrapper around a retained Core Foundation `", stringify!($name), "` reference.")]
186 pub struct $name(pub(crate) crate::cf::base::CFType);
187
188 impl $name {
189 #[doc = concat!("Adopts a +1 retained `", stringify!($name), "` pointer and returns `None` for null.")]
190 #[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.")]
194 #[must_use]
195 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
196 unsafe { crate::cf::base::CFType::from_raw(ptr) }.map(Self)
197 }
198
199 #[doc = concat!("Retains a +0 borrowed `", stringify!($name), "` pointer and returns an owned wrapper.")]
200 #[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.")]
204 #[must_use]
205 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
206 unsafe { crate::cf::base::CFType::from_raw_borrowed(ptr) }.map(Self)
207 }
208
209 #[must_use]
211 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
212 self.0.as_ptr()
213 }
214
215 #[doc = concat!("Returns the Core Foundation type ID for `", stringify!($name), "`.")]
216 #[must_use]
217 pub fn type_id() -> usize {
218 unsafe { crate::ffi::$type_id_fn() }
219 }
220
221 #[must_use]
223 pub fn into_cf_type(self) -> crate::cf::base::CFType {
224 self.0
225 }
226 }
227
228 unsafe impl crate::cf::base::AsCFType for $name {
229 fn as_ptr(&self) -> *mut std::ffi::c_void {
230 self.as_ptr()
231 }
232 }
233
234 impl std::fmt::Debug for $name {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 f.debug_struct(stringify!($name))
237 .field("ptr", &self.as_ptr())
238 .field("description", &self.0.description())
239 .finish()
240 }
241 }
242 };
243}
244
245pub(crate) use impl_cf_type_wrapper;