1#![allow(clippy::missing_panics_doc)]
4
5use super::base::{impl_cf_type_wrapper, AsCFType, CFType, SwiftObject};
40use super::CFString;
41use crate::{ffi, utils::panic_safe};
42use std::ffi::c_void;
43use std::fmt;
44
45impl_cf_type_wrapper!(CFArray, cf_array_get_type_id);
46impl_cf_type_wrapper!(CFDictionary, cf_dictionary_get_type_id);
47pub type CFDict = CFDictionary;
48impl_cf_type_wrapper!(CFBag, cf_bag_get_type_id);
49impl_cf_type_wrapper!(CFSet, cf_set_get_type_id);
50impl_cf_type_wrapper!(CFMutableSet, cf_set_get_type_id);
51impl_cf_type_wrapper!(CFAttributedString, cf_attributed_string_get_type_id);
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
56#[repr(i32)]
57pub enum CFSetCallbacks {
58 #[default]
60 Type = 0,
61 CopyString = 1,
63}
64
65type CFSetApplyTask<'a> = Box<dyn FnMut(CFType) + 'a>;
66
67extern "C" fn cf_set_apply_trampoline(value: *mut c_void, context: *mut c_void) {
68 if context.is_null() {
69 return;
70 }
71 let callback = unsafe { &mut *context.cast::<CFSetApplyTask<'_>>() };
72 if let Some(value) = CFType::from_raw(value) {
73 panic_safe::catch_user_panic("CFSet::for_each", || callback(value));
74 }
75}
76
77impl CFArray {
78 #[must_use]
80 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
81 let raw_values: Vec<*mut std::ffi::c_void> =
82 values.iter().map(|value| value.as_ptr()).collect();
83 let ptr = unsafe { ffi::cf_array_create(raw_values.as_ptr(), raw_values.len()) };
84 Self::from_raw(ptr).expect("CFArrayCreate returned NULL")
85 }
86
87 #[must_use]
89 pub fn len(&self) -> usize {
90 unsafe { ffi::cf_array_get_count(self.as_ptr()) }
91 }
92
93 #[must_use]
95 pub fn is_empty(&self) -> bool {
96 self.len() == 0
97 }
98
99 #[must_use]
101 pub fn get(&self, index: usize) -> Option<CFType> {
102 let ptr = unsafe { ffi::cf_array_get_value_at_index(self.as_ptr(), index) };
103 CFType::from_raw(ptr)
104 }
105
106 #[must_use]
108 pub fn values(&self) -> Vec<CFType> {
109 (0..self.len())
110 .filter_map(|index| self.get(index))
111 .collect()
112 }
113}
114
115impl CFDictionary {
116 #[must_use]
118 pub fn from_pairs(pairs: &[(&dyn AsCFType, &dyn AsCFType)]) -> Self {
119 let keys: Vec<*mut std::ffi::c_void> = pairs.iter().map(|(key, _)| key.as_ptr()).collect();
120 let values: Vec<*mut std::ffi::c_void> =
121 pairs.iter().map(|(_, value)| value.as_ptr()).collect();
122 let ptr = unsafe { ffi::cf_dictionary_create(keys.as_ptr(), values.as_ptr(), pairs.len()) };
123 Self::from_raw(ptr).expect("CFDictionaryCreate returned NULL")
124 }
125
126 #[must_use]
128 pub fn len(&self) -> usize {
129 unsafe { ffi::cf_dictionary_get_count(self.as_ptr()) }
130 }
131
132 #[must_use]
134 pub fn is_empty(&self) -> bool {
135 self.len() == 0
136 }
137
138 #[must_use]
140 pub fn contains_key(&self, key: &dyn AsCFType) -> bool {
141 unsafe { ffi::cf_dictionary_contains_key(self.as_ptr(), key.as_ptr()) }
142 }
143
144 #[must_use]
146 pub fn get(&self, key: &dyn AsCFType) -> Option<CFType> {
147 let ptr = unsafe { ffi::cf_dictionary_get_value(self.as_ptr(), key.as_ptr()) };
148 CFType::from_raw(ptr)
149 }
150
151 #[must_use]
153 pub fn keys(&self) -> CFArray {
154 let ptr = unsafe { ffi::cf_dictionary_copy_keys(self.as_ptr()) };
155 CFArray::from_raw(ptr).expect("CFDictionary keys array should be non-null")
156 }
157
158 #[must_use]
160 pub fn values(&self) -> CFArray {
161 let ptr = unsafe { ffi::cf_dictionary_copy_values(self.as_ptr()) };
162 CFArray::from_raw(ptr).expect("CFDictionary values array should be non-null")
163 }
164}
165
166impl CFBag {
167 #[must_use]
169 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
170 let raw_values: Vec<*mut std::ffi::c_void> =
171 values.iter().map(|value| value.as_ptr()).collect();
172 let ptr = unsafe { ffi::cf_bag_create(raw_values.as_ptr(), raw_values.len()) };
173 Self::from_raw(ptr).expect("CFBagCreate returned NULL")
174 }
175
176 #[must_use]
178 pub fn len(&self) -> usize {
179 unsafe { ffi::cf_bag_get_count(self.as_ptr()) }
180 }
181
182 #[must_use]
184 pub fn is_empty(&self) -> bool {
185 self.len() == 0
186 }
187
188 #[must_use]
190 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
191 unsafe { ffi::cf_bag_contains_value(self.as_ptr(), candidate.as_ptr()) }
192 }
193
194 #[must_use]
196 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
197 unsafe { ffi::cf_bag_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
198 }
199}
200
201impl CFSet {
202 #[must_use]
204 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
205 Self::from_values_with_callbacks(values, CFSetCallbacks::Type)
206 }
207
208 #[must_use]
210 pub fn from_values_with_callbacks(values: &[&dyn AsCFType], callbacks: CFSetCallbacks) -> Self {
211 let raw_values: Vec<*mut c_void> = values.iter().map(|value| value.as_ptr()).collect();
212 let ptr = unsafe { ffi::cf_set_create(raw_values.as_ptr(), raw_values.len(), callbacks as i32) };
213 Self::from_raw(ptr).expect("CFSetCreate returned NULL")
214 }
215
216 #[must_use]
218 pub fn copy(&self) -> Self {
219 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
220 Self::from_raw(ptr).expect("CFSetCreateCopy returned NULL")
221 }
222
223 #[must_use]
225 pub fn mutable_copy(&self, capacity: usize) -> CFMutableSet {
226 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
227 CFMutableSet::from_raw(ptr).expect("CFSetCreateMutableCopy returned NULL")
228 }
229
230 #[must_use]
232 pub fn len(&self) -> usize {
233 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
234 }
235
236 #[must_use]
238 pub fn is_empty(&self) -> bool {
239 self.len() == 0
240 }
241
242 #[must_use]
244 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
245 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
246 }
247
248 #[must_use]
250 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
251 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
252 }
253
254 #[must_use]
256 pub fn get(&self, candidate: &dyn AsCFType) -> Option<CFType> {
257 let ptr = unsafe { ffi::cf_set_get_value(self.as_ptr(), candidate.as_ptr()) };
258 CFType::from_raw(ptr)
259 }
260
261 #[must_use]
263 pub fn get_if_present(&self, candidate: &dyn AsCFType) -> Option<CFType> {
264 let mut ptr = std::ptr::null_mut();
265 let present = unsafe {
266 ffi::cf_set_get_value_if_present(self.as_ptr(), candidate.as_ptr(), &mut ptr)
267 };
268 present.then(|| CFType::from_raw(ptr)).flatten()
269 }
270
271 #[must_use]
273 pub fn values(&self) -> Vec<CFType> {
274 let len = self.len();
275 let mut raw_values = vec![std::ptr::null_mut(); len];
276 if !raw_values.is_empty() {
277 unsafe { ffi::cf_set_get_values(self.as_ptr(), raw_values.as_mut_ptr()) };
278 }
279 raw_values
280 .into_iter()
281 .filter_map(CFType::from_raw)
282 .collect()
283 }
284
285 pub fn for_each<F>(&self, callback: F)
287 where
288 F: FnMut(CFType),
289 {
290 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
291 unsafe {
292 ffi::cf_set_apply_function(
293 self.as_ptr(),
294 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
295 cf_set_apply_trampoline,
296 );
297 }
298 }
299}
300
301impl CFMutableSet {
302 #[must_use]
304 pub fn new() -> Self {
305 Self::with_callbacks(0, CFSetCallbacks::Type)
306 }
307
308 #[must_use]
310 pub fn with_callbacks(capacity: usize, callbacks: CFSetCallbacks) -> Self {
311 let ptr = unsafe { ffi::cf_set_create_mutable(capacity, callbacks as i32) };
312 Self::from_raw(ptr).expect("CFSetCreateMutable returned NULL")
313 }
314
315 #[must_use]
317 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
318 Self::from_values_with_callbacks(values, CFSetCallbacks::Type)
319 }
320
321 #[must_use]
323 pub fn from_values_with_callbacks(values: &[&dyn AsCFType], callbacks: CFSetCallbacks) -> Self {
324 let set = Self::with_callbacks(values.len(), callbacks);
325 for value in values {
326 set.add(*value);
327 }
328 set
329 }
330
331 #[must_use]
333 pub fn copy(&self) -> CFSet {
334 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
335 CFSet::from_raw(ptr).expect("CFSetCreateCopy returned NULL")
336 }
337
338 #[must_use]
340 pub fn mutable_copy(&self, capacity: usize) -> Self {
341 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
342 Self::from_raw(ptr).expect("CFSetCreateMutableCopy returned NULL")
343 }
344
345 #[must_use]
347 pub fn len(&self) -> usize {
348 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
349 }
350
351 #[must_use]
353 pub fn is_empty(&self) -> bool {
354 self.len() == 0
355 }
356
357 #[must_use]
359 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
360 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
361 }
362
363 #[must_use]
365 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
366 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
367 }
368
369 #[must_use]
371 pub fn values(&self) -> Vec<CFType> {
372 let len = self.len();
373 let mut raw_values = vec![std::ptr::null_mut(); len];
374 if !raw_values.is_empty() {
375 unsafe { ffi::cf_set_get_values(self.as_ptr(), raw_values.as_mut_ptr()) };
376 }
377 raw_values
378 .into_iter()
379 .filter_map(CFType::from_raw)
380 .collect()
381 }
382
383 pub fn add(&self, candidate: &dyn AsCFType) {
385 unsafe { ffi::cf_set_add_value(self.as_ptr(), candidate.as_ptr()) };
386 }
387
388 pub fn replace(&self, candidate: &dyn AsCFType) {
390 unsafe { ffi::cf_set_replace_value(self.as_ptr(), candidate.as_ptr()) };
391 }
392
393 pub fn set(&self, candidate: &dyn AsCFType) {
395 unsafe { ffi::cf_set_set_value(self.as_ptr(), candidate.as_ptr()) };
396 }
397
398 pub fn remove(&self, candidate: &dyn AsCFType) {
400 unsafe { ffi::cf_set_remove_value(self.as_ptr(), candidate.as_ptr()) };
401 }
402
403 pub fn clear(&self) {
405 unsafe { ffi::cf_set_remove_all_values(self.as_ptr()) };
406 }
407
408 pub fn for_each<F>(&self, callback: F)
410 where
411 F: FnMut(CFType),
412 {
413 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
414 unsafe {
415 ffi::cf_set_apply_function(
416 self.as_ptr(),
417 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
418 cf_set_apply_trampoline,
419 );
420 }
421 }
422}
423
424impl Default for CFMutableSet {
425 fn default() -> Self {
426 Self::new()
427 }
428}
429
430impl CFAttributedString {
431 #[must_use]
433 pub fn new(string: &CFString) -> Self {
434 let ptr = unsafe { ffi::cf_attributed_string_create(string.as_ptr()) };
435 Self::from_raw(ptr).expect("CFAttributedStringCreate returned NULL")
436 }
437
438 #[must_use]
440 pub fn string(&self) -> CFString {
441 let ptr = unsafe { ffi::cf_attributed_string_get_string(self.as_ptr()) };
442 CFString::from_raw(ptr).expect("CFAttributedStringGetString returned NULL")
443 }
444
445 #[must_use]
447 pub fn len(&self) -> usize {
448 unsafe { ffi::cf_attributed_string_get_length(self.as_ptr()) }
449 }
450
451 #[must_use]
453 pub fn is_empty(&self) -> bool {
454 self.len() == 0
455 }
456}
457
458#[derive(Clone, PartialEq, Eq, Hash)]
460pub struct CFTree(SwiftObject);
461
462impl CFTree {
463 #[must_use]
465 pub fn new(value: Option<&dyn AsCFType>) -> Self {
466 let ptr =
467 unsafe { ffi::cf_tree_create(value.map_or(std::ptr::null_mut(), AsCFType::as_ptr)) };
468 Self(SwiftObject::from_raw(ptr).expect("tree bridge returned NULL"))
469 }
470
471 #[must_use]
472 pub(crate) fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
473 SwiftObject::from_raw(ptr).map(Self)
474 }
475
476 #[must_use]
478 pub(crate) const fn as_ptr(&self) -> *mut std::ffi::c_void {
479 self.0.as_ptr()
480 }
481
482 pub fn append_child(&self, child: &Self) {
484 unsafe { ffi::cf_tree_append_child(self.as_ptr(), child.as_ptr()) };
485 }
486
487 #[must_use]
489 pub fn child_count(&self) -> usize {
490 unsafe { ffi::cf_tree_get_child_count(self.as_ptr()) }
491 }
492
493 #[must_use]
495 pub fn child_at(&self, index: usize) -> Option<Self> {
496 let ptr = unsafe { ffi::cf_tree_get_child_at_index(self.as_ptr(), index) };
497 Self::from_raw(ptr)
498 }
499
500 #[must_use]
502 pub fn value(&self) -> Option<CFType> {
503 let ptr = unsafe { ffi::cf_tree_copy_value(self.as_ptr()) };
504 CFType::from_raw(ptr)
505 }
506}
507
508impl fmt::Debug for CFTree {
509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510 f.debug_struct("CFTree")
511 .field("ptr", &self.as_ptr())
512 .field("child_count", &self.child_count())
513 .finish()
514 }
515}