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) = CFType::from_raw(value) {
74 panic_safe::catch_user_panic("CFSet::for_each", || callback(value));
75 }
76}
77
78impl CFArray {
79 #[must_use]
81 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
82 let raw_values: Vec<*mut std::ffi::c_void> =
83 values.iter().map(|value| value.as_ptr()).collect();
84 let ptr = unsafe { ffi::cf_array_create(raw_values.as_ptr(), raw_values.len()) };
85 Self::from_raw(ptr).expect("CFArrayCreate returned NULL")
86 }
87
88 #[must_use]
90 pub fn len(&self) -> usize {
91 unsafe { ffi::cf_array_get_count(self.as_ptr()) }
92 }
93
94 #[must_use]
96 pub fn is_empty(&self) -> bool {
97 self.len() == 0
98 }
99
100 #[must_use]
102 pub fn get(&self, index: usize) -> Option<CFType> {
103 let ptr = unsafe { ffi::cf_array_get_value_at_index(self.as_ptr(), index) };
104 CFType::from_raw(ptr)
105 }
106
107 #[must_use]
109 pub fn values(&self) -> Vec<CFType> {
110 (0..self.len())
111 .filter_map(|index| self.get(index))
112 .collect()
113 }
114}
115
116impl CFDictionary {
117 #[must_use]
119 pub fn from_pairs(pairs: &[(&dyn AsCFType, &dyn AsCFType)]) -> Self {
120 let keys: Vec<*mut std::ffi::c_void> = pairs.iter().map(|(key, _)| key.as_ptr()).collect();
121 let values: Vec<*mut std::ffi::c_void> =
122 pairs.iter().map(|(_, value)| value.as_ptr()).collect();
123 let ptr = unsafe { ffi::cf_dictionary_create(keys.as_ptr(), values.as_ptr(), pairs.len()) };
124 Self::from_raw(ptr).expect("CFDictionaryCreate returned NULL")
125 }
126
127 #[must_use]
129 pub fn len(&self) -> usize {
130 unsafe { ffi::cf_dictionary_get_count(self.as_ptr()) }
131 }
132
133 #[must_use]
135 pub fn is_empty(&self) -> bool {
136 self.len() == 0
137 }
138
139 #[must_use]
141 pub fn contains_key(&self, key: &dyn AsCFType) -> bool {
142 unsafe { ffi::cf_dictionary_contains_key(self.as_ptr(), key.as_ptr()) }
143 }
144
145 #[must_use]
147 pub fn get(&self, key: &dyn AsCFType) -> Option<CFType> {
148 let ptr = unsafe { ffi::cf_dictionary_get_value(self.as_ptr(), key.as_ptr()) };
149 CFType::from_raw(ptr)
150 }
151
152 #[must_use]
154 pub fn keys(&self) -> CFArray {
155 let ptr = unsafe { ffi::cf_dictionary_copy_keys(self.as_ptr()) };
156 CFArray::from_raw(ptr).expect("CFDictionary keys array should be non-null")
157 }
158
159 #[must_use]
161 pub fn values(&self) -> CFArray {
162 let ptr = unsafe { ffi::cf_dictionary_copy_values(self.as_ptr()) };
163 CFArray::from_raw(ptr).expect("CFDictionary values array should be non-null")
164 }
165}
166
167impl CFBag {
168 #[must_use]
170 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
171 let raw_values: Vec<*mut std::ffi::c_void> =
172 values.iter().map(|value| value.as_ptr()).collect();
173 let ptr = unsafe { ffi::cf_bag_create(raw_values.as_ptr(), raw_values.len()) };
174 Self::from_raw(ptr).expect("CFBagCreate returned NULL")
175 }
176
177 #[must_use]
179 pub fn len(&self) -> usize {
180 unsafe { ffi::cf_bag_get_count(self.as_ptr()) }
181 }
182
183 #[must_use]
185 pub fn is_empty(&self) -> bool {
186 self.len() == 0
187 }
188
189 #[must_use]
191 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
192 unsafe { ffi::cf_bag_contains_value(self.as_ptr(), candidate.as_ptr()) }
193 }
194
195 #[must_use]
197 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
198 unsafe { ffi::cf_bag_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
199 }
200}
201
202impl CFSet {
203 #[must_use]
205 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
206 Self::from_values_with_callbacks(values, CFSetCallbacks::Type)
207 }
208
209 #[must_use]
211 pub fn from_values_with_callbacks(values: &[&dyn AsCFType], callbacks: CFSetCallbacks) -> Self {
212 let raw_values: Vec<*mut c_void> = values.iter().map(|value| value.as_ptr()).collect();
213 let ptr =
214 unsafe { ffi::cf_set_create(raw_values.as_ptr(), raw_values.len(), callbacks as i32) };
215 Self::from_raw(ptr).expect("CFSetCreate returned NULL")
216 }
217
218 #[must_use]
220 pub fn copy(&self) -> Self {
221 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
222 Self::from_raw(ptr).expect("CFSetCreateCopy returned NULL")
223 }
224
225 #[must_use]
227 pub fn mutable_copy(&self, capacity: usize) -> CFMutableSet {
228 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
229 CFMutableSet::from_raw(ptr).expect("CFSetCreateMutableCopy returned NULL")
230 }
231
232 #[must_use]
234 pub fn len(&self) -> usize {
235 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
236 }
237
238 #[must_use]
240 pub fn is_empty(&self) -> bool {
241 self.len() == 0
242 }
243
244 #[must_use]
246 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
247 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
248 }
249
250 #[must_use]
252 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
253 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
254 }
255
256 #[must_use]
258 pub fn get(&self, candidate: &dyn AsCFType) -> Option<CFType> {
259 let ptr = unsafe { ffi::cf_set_get_value(self.as_ptr(), candidate.as_ptr()) };
260 CFType::from_raw(ptr)
261 }
262
263 #[must_use]
265 pub fn get_if_present(&self, candidate: &dyn AsCFType) -> Option<CFType> {
266 let mut ptr = std::ptr::null_mut();
267 let present = unsafe {
268 ffi::cf_set_get_value_if_present(self.as_ptr(), candidate.as_ptr(), &mut ptr)
269 };
270 present.then(|| CFType::from_raw(ptr)).flatten()
271 }
272
273 #[must_use]
275 pub fn values(&self) -> Vec<CFType> {
276 let len = self.len();
277 let mut raw_values = vec![std::ptr::null_mut(); len];
278 if !raw_values.is_empty() {
279 unsafe { ffi::cf_set_get_values(self.as_ptr(), raw_values.as_mut_ptr()) };
280 }
281 raw_values
282 .into_iter()
283 .filter_map(CFType::from_raw)
284 .collect()
285 }
286
287 pub fn for_each<F>(&self, callback: F)
289 where
290 F: FnMut(CFType),
291 {
292 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
293 unsafe {
294 ffi::cf_set_apply_function(
295 self.as_ptr(),
296 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
297 cf_set_apply_trampoline,
298 );
299 }
300 }
301}
302
303impl CFMutableSet {
304 #[must_use]
306 pub fn new() -> Self {
307 Self::with_callbacks(0, CFSetCallbacks::Type)
308 }
309
310 #[must_use]
312 pub fn with_callbacks(capacity: usize, callbacks: CFSetCallbacks) -> Self {
313 let ptr = unsafe { ffi::cf_set_create_mutable(capacity, callbacks as i32) };
314 Self::from_raw(ptr).expect("CFSetCreateMutable returned NULL")
315 }
316
317 #[must_use]
319 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
320 Self::from_values_with_callbacks(values, CFSetCallbacks::Type)
321 }
322
323 #[must_use]
325 pub fn from_values_with_callbacks(values: &[&dyn AsCFType], callbacks: CFSetCallbacks) -> Self {
326 let set = Self::with_callbacks(values.len(), callbacks);
327 for value in values {
328 set.add(*value);
329 }
330 set
331 }
332
333 #[must_use]
335 pub fn copy(&self) -> CFSet {
336 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
337 CFSet::from_raw(ptr).expect("CFSetCreateCopy returned NULL")
338 }
339
340 #[must_use]
342 pub fn mutable_copy(&self, capacity: usize) -> Self {
343 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
344 Self::from_raw(ptr).expect("CFSetCreateMutableCopy returned NULL")
345 }
346
347 #[must_use]
349 pub fn len(&self) -> usize {
350 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
351 }
352
353 #[must_use]
355 pub fn is_empty(&self) -> bool {
356 self.len() == 0
357 }
358
359 #[must_use]
361 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
362 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
363 }
364
365 #[must_use]
367 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
368 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
369 }
370
371 #[must_use]
373 pub fn values(&self) -> Vec<CFType> {
374 let len = self.len();
375 let mut raw_values = vec![std::ptr::null_mut(); len];
376 if !raw_values.is_empty() {
377 unsafe { ffi::cf_set_get_values(self.as_ptr(), raw_values.as_mut_ptr()) };
378 }
379 raw_values
380 .into_iter()
381 .filter_map(CFType::from_raw)
382 .collect()
383 }
384
385 pub fn add(&self, candidate: &dyn AsCFType) {
387 unsafe { ffi::cf_set_add_value(self.as_ptr(), candidate.as_ptr()) };
388 }
389
390 pub fn replace(&self, candidate: &dyn AsCFType) {
392 unsafe { ffi::cf_set_replace_value(self.as_ptr(), candidate.as_ptr()) };
393 }
394
395 pub fn set(&self, candidate: &dyn AsCFType) {
397 unsafe { ffi::cf_set_set_value(self.as_ptr(), candidate.as_ptr()) };
398 }
399
400 pub fn remove(&self, candidate: &dyn AsCFType) {
402 unsafe { ffi::cf_set_remove_value(self.as_ptr(), candidate.as_ptr()) };
403 }
404
405 pub fn clear(&self) {
407 unsafe { ffi::cf_set_remove_all_values(self.as_ptr()) };
408 }
409
410 pub fn for_each<F>(&self, callback: F)
412 where
413 F: FnMut(CFType),
414 {
415 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
416 unsafe {
417 ffi::cf_set_apply_function(
418 self.as_ptr(),
419 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
420 cf_set_apply_trampoline,
421 );
422 }
423 }
424}
425
426impl Default for CFMutableSet {
427 fn default() -> Self {
428 Self::new()
429 }
430}
431
432impl CFAttributedString {
433 #[must_use]
435 pub fn new(string: &CFString) -> Self {
436 let ptr = unsafe { ffi::cf_attributed_string_create(string.as_ptr()) };
437 Self::from_raw(ptr).expect("CFAttributedStringCreate returned NULL")
438 }
439
440 #[must_use]
442 pub fn string(&self) -> CFString {
443 let ptr = unsafe { ffi::cf_attributed_string_get_string(self.as_ptr()) };
444 CFString::from_raw(ptr).expect("CFAttributedStringGetString returned NULL")
445 }
446
447 #[must_use]
449 pub fn len(&self) -> usize {
450 unsafe { ffi::cf_attributed_string_get_length(self.as_ptr()) }
451 }
452
453 #[must_use]
455 pub fn is_empty(&self) -> bool {
456 self.len() == 0
457 }
458}
459
460#[derive(Clone, PartialEq, Eq, Hash)]
462pub struct CFTree(SwiftObject);
463
464impl CFTree {
465 #[must_use]
467 pub fn new(value: Option<&dyn AsCFType>) -> Self {
468 let ptr =
469 unsafe { ffi::cf_tree_create(value.map_or(std::ptr::null_mut(), AsCFType::as_ptr)) };
470 Self(SwiftObject::from_raw(ptr).expect("tree bridge returned NULL"))
471 }
472
473 #[must_use]
475 pub(crate) fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
476 SwiftObject::from_raw(ptr).map(Self)
477 }
478
479 #[must_use]
481 pub(crate) const fn as_ptr(&self) -> *mut std::ffi::c_void {
482 self.0.as_ptr()
483 }
484
485 pub fn append_child(&self, child: &Self) {
487 unsafe { ffi::cf_tree_append_child(self.as_ptr(), child.as_ptr()) };
488 }
489
490 #[must_use]
492 pub fn child_count(&self) -> usize {
493 unsafe { ffi::cf_tree_get_child_count(self.as_ptr()) }
494 }
495
496 #[must_use]
498 pub fn child_at(&self, index: usize) -> Option<Self> {
499 let ptr = unsafe { ffi::cf_tree_get_child_at_index(self.as_ptr(), index) };
500 Self::from_raw(ptr)
501 }
502
503 #[must_use]
505 pub fn value(&self) -> Option<CFType> {
506 let ptr = unsafe { ffi::cf_tree_copy_value(self.as_ptr()) };
507 CFType::from_raw(ptr)
508 }
509}
510
511impl fmt::Debug for CFTree {
512 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513 f.debug_struct("CFTree")
514 .field("ptr", &self.as_ptr())
515 .field("child_count", &self.child_count())
516 .finish()
517 }
518}