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 =
213 unsafe { ffi::cf_set_create(raw_values.as_ptr(), raw_values.len(), callbacks as i32) };
214 Self::from_raw(ptr).expect("CFSetCreate returned NULL")
215 }
216
217 #[must_use]
219 pub fn copy(&self) -> Self {
220 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
221 Self::from_raw(ptr).expect("CFSetCreateCopy returned NULL")
222 }
223
224 #[must_use]
226 pub fn mutable_copy(&self, capacity: usize) -> CFMutableSet {
227 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
228 CFMutableSet::from_raw(ptr).expect("CFSetCreateMutableCopy returned NULL")
229 }
230
231 #[must_use]
233 pub fn len(&self) -> usize {
234 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
235 }
236
237 #[must_use]
239 pub fn is_empty(&self) -> bool {
240 self.len() == 0
241 }
242
243 #[must_use]
245 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
246 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
247 }
248
249 #[must_use]
251 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
252 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
253 }
254
255 #[must_use]
257 pub fn get(&self, candidate: &dyn AsCFType) -> Option<CFType> {
258 let ptr = unsafe { ffi::cf_set_get_value(self.as_ptr(), candidate.as_ptr()) };
259 CFType::from_raw(ptr)
260 }
261
262 #[must_use]
264 pub fn get_if_present(&self, candidate: &dyn AsCFType) -> Option<CFType> {
265 let mut ptr = std::ptr::null_mut();
266 let present = unsafe {
267 ffi::cf_set_get_value_if_present(self.as_ptr(), candidate.as_ptr(), &mut ptr)
268 };
269 present.then(|| CFType::from_raw(ptr)).flatten()
270 }
271
272 #[must_use]
274 pub fn values(&self) -> Vec<CFType> {
275 let len = self.len();
276 let mut raw_values = vec![std::ptr::null_mut(); len];
277 if !raw_values.is_empty() {
278 unsafe { ffi::cf_set_get_values(self.as_ptr(), raw_values.as_mut_ptr()) };
279 }
280 raw_values
281 .into_iter()
282 .filter_map(CFType::from_raw)
283 .collect()
284 }
285
286 pub fn for_each<F>(&self, callback: F)
288 where
289 F: FnMut(CFType),
290 {
291 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
292 unsafe {
293 ffi::cf_set_apply_function(
294 self.as_ptr(),
295 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
296 cf_set_apply_trampoline,
297 );
298 }
299 }
300}
301
302impl CFMutableSet {
303 #[must_use]
305 pub fn new() -> Self {
306 Self::with_callbacks(0, CFSetCallbacks::Type)
307 }
308
309 #[must_use]
311 pub fn with_callbacks(capacity: usize, callbacks: CFSetCallbacks) -> Self {
312 let ptr = unsafe { ffi::cf_set_create_mutable(capacity, callbacks as i32) };
313 Self::from_raw(ptr).expect("CFSetCreateMutable returned NULL")
314 }
315
316 #[must_use]
318 pub fn from_values(values: &[&dyn AsCFType]) -> Self {
319 Self::from_values_with_callbacks(values, CFSetCallbacks::Type)
320 }
321
322 #[must_use]
324 pub fn from_values_with_callbacks(values: &[&dyn AsCFType], callbacks: CFSetCallbacks) -> Self {
325 let set = Self::with_callbacks(values.len(), callbacks);
326 for value in values {
327 set.add(*value);
328 }
329 set
330 }
331
332 #[must_use]
334 pub fn copy(&self) -> CFSet {
335 let ptr = unsafe { ffi::cf_set_create_copy(self.as_ptr()) };
336 CFSet::from_raw(ptr).expect("CFSetCreateCopy returned NULL")
337 }
338
339 #[must_use]
341 pub fn mutable_copy(&self, capacity: usize) -> Self {
342 let ptr = unsafe { ffi::cf_set_create_mutable_copy(self.as_ptr(), capacity) };
343 Self::from_raw(ptr).expect("CFSetCreateMutableCopy returned NULL")
344 }
345
346 #[must_use]
348 pub fn len(&self) -> usize {
349 unsafe { ffi::cf_set_get_count(self.as_ptr()) }
350 }
351
352 #[must_use]
354 pub fn is_empty(&self) -> bool {
355 self.len() == 0
356 }
357
358 #[must_use]
360 pub fn contains(&self, candidate: &dyn AsCFType) -> bool {
361 unsafe { ffi::cf_set_contains_value(self.as_ptr(), candidate.as_ptr()) }
362 }
363
364 #[must_use]
366 pub fn count_of_value(&self, candidate: &dyn AsCFType) -> usize {
367 unsafe { ffi::cf_set_get_count_of_value(self.as_ptr(), candidate.as_ptr()) }
368 }
369
370 #[must_use]
372 pub fn values(&self) -> Vec<CFType> {
373 let len = self.len();
374 let mut raw_values = vec![std::ptr::null_mut(); len];
375 if !raw_values.is_empty() {
376 unsafe { ffi::cf_set_get_values(self.as_ptr(), raw_values.as_mut_ptr()) };
377 }
378 raw_values
379 .into_iter()
380 .filter_map(CFType::from_raw)
381 .collect()
382 }
383
384 pub fn add(&self, candidate: &dyn AsCFType) {
386 unsafe { ffi::cf_set_add_value(self.as_ptr(), candidate.as_ptr()) };
387 }
388
389 pub fn replace(&self, candidate: &dyn AsCFType) {
391 unsafe { ffi::cf_set_replace_value(self.as_ptr(), candidate.as_ptr()) };
392 }
393
394 pub fn set(&self, candidate: &dyn AsCFType) {
396 unsafe { ffi::cf_set_set_value(self.as_ptr(), candidate.as_ptr()) };
397 }
398
399 pub fn remove(&self, candidate: &dyn AsCFType) {
401 unsafe { ffi::cf_set_remove_value(self.as_ptr(), candidate.as_ptr()) };
402 }
403
404 pub fn clear(&self) {
406 unsafe { ffi::cf_set_remove_all_values(self.as_ptr()) };
407 }
408
409 pub fn for_each<F>(&self, callback: F)
411 where
412 F: FnMut(CFType),
413 {
414 let mut callback: CFSetApplyTask<'_> = Box::new(callback);
415 unsafe {
416 ffi::cf_set_apply_function(
417 self.as_ptr(),
418 std::ptr::addr_of_mut!(callback).cast::<c_void>(),
419 cf_set_apply_trampoline,
420 );
421 }
422 }
423}
424
425impl Default for CFMutableSet {
426 fn default() -> Self {
427 Self::new()
428 }
429}
430
431impl CFAttributedString {
432 #[must_use]
434 pub fn new(string: &CFString) -> Self {
435 let ptr = unsafe { ffi::cf_attributed_string_create(string.as_ptr()) };
436 Self::from_raw(ptr).expect("CFAttributedStringCreate returned NULL")
437 }
438
439 #[must_use]
441 pub fn string(&self) -> CFString {
442 let ptr = unsafe { ffi::cf_attributed_string_get_string(self.as_ptr()) };
443 CFString::from_raw(ptr).expect("CFAttributedStringGetString returned NULL")
444 }
445
446 #[must_use]
448 pub fn len(&self) -> usize {
449 unsafe { ffi::cf_attributed_string_get_length(self.as_ptr()) }
450 }
451
452 #[must_use]
454 pub fn is_empty(&self) -> bool {
455 self.len() == 0
456 }
457}
458
459#[derive(Clone, PartialEq, Eq, Hash)]
461pub struct CFTree(SwiftObject);
462
463impl CFTree {
464 #[must_use]
466 pub fn new(value: Option<&dyn AsCFType>) -> Self {
467 let ptr =
468 unsafe { ffi::cf_tree_create(value.map_or(std::ptr::null_mut(), AsCFType::as_ptr)) };
469 Self(SwiftObject::from_raw(ptr).expect("tree bridge returned NULL"))
470 }
471
472 #[must_use]
473 pub(crate) fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
474 SwiftObject::from_raw(ptr).map(Self)
475 }
476
477 #[must_use]
479 pub(crate) const fn as_ptr(&self) -> *mut std::ffi::c_void {
480 self.0.as_ptr()
481 }
482
483 pub fn append_child(&self, child: &Self) {
485 unsafe { ffi::cf_tree_append_child(self.as_ptr(), child.as_ptr()) };
486 }
487
488 #[must_use]
490 pub fn child_count(&self) -> usize {
491 unsafe { ffi::cf_tree_get_child_count(self.as_ptr()) }
492 }
493
494 #[must_use]
496 pub fn child_at(&self, index: usize) -> Option<Self> {
497 let ptr = unsafe { ffi::cf_tree_get_child_at_index(self.as_ptr(), index) };
498 Self::from_raw(ptr)
499 }
500
501 #[must_use]
503 pub fn value(&self) -> Option<CFType> {
504 let ptr = unsafe { ffi::cf_tree_copy_value(self.as_ptr()) };
505 CFType::from_raw(ptr)
506 }
507}
508
509impl fmt::Debug for CFTree {
510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511 f.debug_struct("CFTree")
512 .field("ptr", &self.as_ptr())
513 .field("child_count", &self.child_count())
514 .finish()
515 }
516}