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;
49impl_cf_type_wrapper!(CFBag, cf_bag_get_type_id);
50impl_cf_type_wrapper!(CFSet, cf_set_get_type_id);
51impl_cf_type_wrapper!(CFMutableSet, cf_set_get_type_id);
52impl_cf_type_wrapper!(CFAttributedString, cf_attributed_string_get_type_id);
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
57#[repr(i32)]
58pub enum CFSetCallbacks {
59 #[default]
61 Type = 0,
62 CopyString = 1,
64}
65
66type CFSetApplyTask<'a> = Box<dyn FnMut(CFType) + 'a>;
67
68extern "C" fn cf_set_apply_trampoline(value: *mut c_void, context: *mut c_void) {
69 if context.is_null() {
70 return;
71 }
72 let callback = unsafe { &mut *context.cast::<CFSetApplyTask<'_>>() };
73 if let Some(value) = unsafe { CFType::from_raw(value) } {
74 panic_safe::catch_user_panic("CFSet::for_each", || callback(value));
75 }
76}
77
78fn copy_set_values(set: *mut c_void, expected_len: usize) -> Vec<CFType> {
79 let mut raw_values: Vec<*mut c_void> = vec![std::ptr::null_mut(); expected_len];
80 loop {
81 let capacity = raw_values.len();
82 let buffer = if capacity == 0 {
83 std::ptr::null_mut()
84 } else {
85 raw_values.as_mut_ptr()
86 };
87 let len = unsafe { ffi::acf_cf_set_copy_values(set, buffer, capacity) };
88 if len <= capacity {
89 raw_values.truncate(len);
90 return raw_values
91 .into_iter()
92 .filter_map(|ptr| unsafe { CFType::from_raw(ptr) })
93 .collect();
94 }
95 raw_values.resize(len, std::ptr::null_mut());
96 }
97}
98
99impl CFArray {
100 #[must_use]
102 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
103 let raw_values: Vec<*mut std::ffi::c_void> =
104 values.iter().map(|value| value.as_ptr()).collect();
105 let ptr = unsafe { ffi::cf_array_create(raw_values.as_ptr(), raw_values.len()) };
106 unsafe { Self::from_raw(ptr) }.expect("CFArrayCreate returned NULL")
107 }
108
109 #[must_use]
111 pub fn len(&self) -> usize {
112 unsafe { ffi::cf_array_get_count(self.as_ptr()) }
113 }
114
115 #[must_use]
117 pub fn is_empty(&self) -> bool {
118 self.len() == 0
119 }
120
121 #[must_use]
123 pub fn get(&self, index: usize) -> Option<CFType> {
124 let ptr = unsafe { ffi::cf_array_get_value_at_index(self.as_ptr(), index) };
125 unsafe { CFType::from_raw(ptr) }
126 }
127
128 #[must_use]
130 pub fn values(&self) -> Vec<CFType> {
131 (0..self.len())
132 .filter_map(|index| self.get(index))
133 .collect()
134 }
135}
136
137impl CFDictionary {
138 #[must_use]
140 pub fn from_pairs(pairs: &[(&dyn AsCFType, &dyn AsCFType)]) -> Self {
141 let keys: Vec<*mut std::ffi::c_void> = pairs.iter().map(|(key, _)| key.as_ptr()).collect();
142 let values: Vec<*mut std::ffi::c_void> =
143 pairs.iter().map(|(_, value)| value.as_ptr()).collect();
144 let ptr = unsafe { ffi::cf_dictionary_create(keys.as_ptr(), values.as_ptr(), pairs.len()) };
145 unsafe { Self::from_raw(ptr) }.expect("CFDictionaryCreate returned NULL")
146 }
147
148 #[must_use]
150 pub fn len(&self) -> usize {
151 unsafe { ffi::cf_dictionary_get_count(self.as_ptr()) }
152 }
153
154 #[must_use]
156 pub fn is_empty(&self) -> bool {
157 self.len() == 0
158 }
159
160 #[must_use]
162 pub fn contains_key(&self, key: &dyn AsCFType) -> bool {
163 unsafe { ffi::cf_dictionary_contains_key(self.as_ptr(), key.as_ptr()) }
164 }
165
166 #[must_use]
168 pub fn get(&self, key: &dyn AsCFType) -> Option<CFType> {
169 let ptr = unsafe { ffi::cf_dictionary_get_value(self.as_ptr(), key.as_ptr()) };
170 unsafe { CFType::from_raw(ptr) }
171 }
172
173 #[must_use]
175 pub fn keys(&self) -> CFArray {
176 let ptr = unsafe { ffi::cf_dictionary_copy_keys(self.as_ptr()) };
177 unsafe { CFArray::from_raw(ptr) }.expect("CFDictionary keys array should be non-null")
178 }
179
180 #[must_use]
182 pub fn values(&self) -> CFArray {
183 let ptr = unsafe { ffi::cf_dictionary_copy_values(self.as_ptr()) };
184 unsafe { CFArray::from_raw(ptr) }.expect("CFDictionary values array should be non-null")
185 }
186}
187
188impl CFBag {
189 #[must_use]
191 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
192 let raw_values: Vec<*mut std::ffi::c_void> =
193 values.iter().map(|value| value.as_ptr()).collect();
194 let ptr = unsafe { ffi::cf_bag_create(raw_values.as_ptr(), raw_values.len()) };
195 unsafe { Self::from_raw(ptr) }.expect("CFBagCreate returned NULL")
196 }
197
198 #[must_use]
200 pub fn len(&self) -> usize {
201 unsafe { ffi::cf_bag_get_count(self.as_ptr()) }
202 }
203
204 #[must_use]
206 pub fn is_empty(&self) -> bool {
207 self.len() == 0
208 }
209
210 #[must_use]
212 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
213 unsafe { ffi::cf_bag_contains_value(self.as_ptr(), candidate.as_ptr()) }
214 }
215
216 #[must_use]
218 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
219 unsafe { ffi::cf_bag_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
220 }
221}
222
223impl CFSet {
224 #[must_use]
226 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
227 Self::from_values_with_callbacks(values, CFSetCallbacks::Type)
228 }
229
230 #[must_use]
232 pub fn from_values_with_callbacks(values: &[&dyn AsCFType], callbacks: CFSetCallbacks) -> Self {
233 let raw_values: Vec<*mut c_void> = values.iter().map(|value| value.as_ptr()).collect();
234 let ptr =
235 unsafe { ffi::cf_set_create(raw_values.as_ptr(), raw_values.len(), callbacks as i32) };
236 unsafe { Self::from_raw(ptr) }.expect("CFSetCreate returned NULL")
237 }
238
239 #[must_use]
241 pub fn copy(&self) -> Self {
242 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
243 unsafe { Self::from_raw(ptr) }.expect("CFSetCreateCopy returned NULL")
244 }
245
246 #[must_use]
248 pub fn mutable_copy(&self, capacity: usize) -> CFMutableSet {
249 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
250 unsafe { CFMutableSet::from_raw(ptr) }.expect("CFSetCreateMutableCopy returned NULL")
251 }
252
253 #[must_use]
255 pub fn len(&self) -> usize {
256 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
257 }
258
259 #[must_use]
261 pub fn is_empty(&self) -> bool {
262 self.len() == 0
263 }
264
265 #[must_use]
267 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
268 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
269 }
270
271 #[must_use]
273 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
274 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
275 }
276
277 #[must_use]
279 pub fn get(&self, candidate: &dyn AsCFType) -> Option<CFType> {
280 let ptr = unsafe { ffi::cf_set_get_value(self.as_ptr(), candidate.as_ptr()) };
281 unsafe { CFType::from_raw(ptr) }
282 }
283
284 #[must_use]
286 pub fn get_if_present(&self, candidate: &dyn AsCFType) -> Option<CFType> {
287 let mut ptr = std::ptr::null_mut();
288 let present = unsafe {
289 ffi::cf_set_get_value_if_present(self.as_ptr(), candidate.as_ptr(), &raw mut ptr)
290 };
291 present.then(|| unsafe { CFType::from_raw(ptr) }).flatten()
292 }
293
294 #[must_use]
296 pub fn values(&self) -> Vec<CFType> {
297 copy_set_values(self.as_ptr(), self.len())
298 }
299
300 pub fn for_each<F>(&self, callback: F)
302 where
303 F: FnMut(CFType),
304 {
305 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
306 unsafe {
307 ffi::cf_set_apply_function(
308 self.as_ptr(),
309 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
310 cf_set_apply_trampoline,
311 );
312 }
313 }
314}
315
316impl CFMutableSet {
317 #[must_use]
319 pub fn new() -> Self {
320 Self::with_callbacks(0, CFSetCallbacks::Type)
321 }
322
323 #[must_use]
325 pub fn with_callbacks(capacity: usize, callbacks: CFSetCallbacks) -> Self {
326 let ptr = unsafe { ffi::cf_set_create_mutable(capacity, callbacks as i32) };
327 unsafe { Self::from_raw(ptr) }.expect("CFSetCreateMutable returned NULL")
328 }
329
330 #[must_use]
332 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
333 Self::from_values_with_callbacks(values, CFSetCallbacks::Type)
334 }
335
336 #[must_use]
338 pub fn from_values_with_callbacks(values: &[&dyn AsCFType], callbacks: CFSetCallbacks) -> Self {
339 let set = Self::with_callbacks(values.len(), callbacks);
340 for value in values {
341 set.add(*value);
342 }
343 set
344 }
345
346 #[must_use]
348 pub fn copy(&self) -> CFSet {
349 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
350 unsafe { CFSet::from_raw(ptr) }.expect("CFSetCreateCopy returned NULL")
351 }
352
353 #[must_use]
355 pub fn mutable_copy(&self, capacity: usize) -> Self {
356 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
357 unsafe { Self::from_raw(ptr) }.expect("CFSetCreateMutableCopy returned NULL")
358 }
359
360 #[must_use]
362 pub fn len(&self) -> usize {
363 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
364 }
365
366 #[must_use]
368 pub fn is_empty(&self) -> bool {
369 self.len() == 0
370 }
371
372 #[must_use]
374 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
375 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
376 }
377
378 #[must_use]
380 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
381 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
382 }
383
384 #[must_use]
386 pub fn values(&self) -> Vec<CFType> {
387 copy_set_values(self.as_ptr(), self.len())
388 }
389
390 pub fn add(&self, candidate: &dyn AsCFType) {
392 unsafe { ffi::cf_set_add_value(self.as_ptr(), candidate.as_ptr()) };
393 }
394
395 pub fn replace(&self, candidate: &dyn AsCFType) {
397 unsafe { ffi::cf_set_replace_value(self.as_ptr(), candidate.as_ptr()) };
398 }
399
400 pub fn set(&self, candidate: &dyn AsCFType) {
402 unsafe { ffi::cf_set_set_value(self.as_ptr(), candidate.as_ptr()) };
403 }
404
405 pub fn remove(&self, candidate: &dyn AsCFType) {
407 unsafe { ffi::cf_set_remove_value(self.as_ptr(), candidate.as_ptr()) };
408 }
409
410 pub fn clear(&self) {
412 unsafe { ffi::cf_set_remove_all_values(self.as_ptr()) };
413 }
414
415 pub fn for_each<F>(&self, callback: F)
417 where
418 F: FnMut(CFType),
419 {
420 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
421 unsafe {
422 ffi::cf_set_apply_function(
423 self.as_ptr(),
424 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
425 cf_set_apply_trampoline,
426 );
427 }
428 }
429}
430
431impl Default for CFMutableSet {
432 fn default() -> Self {
433 Self::new()
434 }
435}
436
437impl CFAttributedString {
438 #[must_use]
440 pub fn new(string: &CFString) -> Self {
441 let ptr = unsafe { ffi::cf_attributed_string_create(string.as_ptr()) };
442 unsafe { Self::from_raw(ptr) }.expect("CFAttributedStringCreate returned NULL")
443 }
444
445 #[must_use]
447 pub fn string(&self) -> CFString {
448 let ptr = unsafe { ffi::cf_attributed_string_get_string(self.as_ptr()) };
449 unsafe { CFString::from_raw(ptr) }.expect("CFAttributedStringGetString returned NULL")
450 }
451
452 #[must_use]
454 pub fn len(&self) -> usize {
455 unsafe { ffi::cf_attributed_string_get_length(self.as_ptr()) }
456 }
457
458 #[must_use]
460 pub fn is_empty(&self) -> bool {
461 self.len() == 0
462 }
463}
464
465#[derive(Clone, PartialEq, Eq, Hash)]
467pub struct CFTree(SwiftObject);
468
469impl CFTree {
470 #[must_use]
472 pub fn new(value: Option<&dyn AsCFType>) -> Self {
473 let ptr =
474 unsafe { ffi::cf_tree_create(value.map_or(std::ptr::null_mut(), AsCFType::as_ptr)) };
475 Self(SwiftObject::from_raw_owned(ptr).expect("tree bridge returned NULL"))
476 }
477
478 #[must_use]
480 pub(crate) fn from_raw_owned(ptr: *mut std::ffi::c_void) -> Option<Self> {
481 SwiftObject::from_raw_owned(ptr).map(Self)
482 }
483
484 #[must_use]
486 pub(crate) const fn as_ptr(&self) -> *mut std::ffi::c_void {
487 self.0.as_ptr()
488 }
489
490 pub fn append_child(&self, child: &Self) {
492 unsafe { ffi::cf_tree_append_child(self.as_ptr(), child.as_ptr()) };
493 }
494
495 #[must_use]
497 pub fn child_count(&self) -> usize {
498 unsafe { ffi::cf_tree_get_child_count(self.as_ptr()) }
499 }
500
501 #[must_use]
503 pub fn child_at(&self, index: usize) -> Option<Self> {
504 let ptr = unsafe { ffi::cf_tree_get_child_at_index(self.as_ptr(), index) };
505 Self::from_raw_owned(ptr)
506 }
507
508 #[must_use]
510 pub fn value(&self) -> Option<CFType> {
511 let ptr = unsafe { ffi::cf_tree_copy_value(self.as_ptr()) };
512 unsafe { CFType::from_raw(ptr) }
513 }
514}
515
516impl fmt::Debug for CFTree {
517 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
518 f.debug_struct("CFTree")
519 .field("ptr", &self.as_ptr())
520 .field("child_count", &self.child_count())
521 .finish()
522 }
523}