rust_macios/core_foundation/
cf_string.rs

1use std::{
2    borrow::Cow,
3    ffi::{c_double, CStr},
4    fmt,
5};
6
7use libc::{c_char, c_uchar, c_ulong, c_void};
8
9use bitflags::bitflags;
10
11use crate::{
12    core_foundation::CFRange,
13    declare_CFType,
14    kernel::{Boolean, SInt32, UInt32, UInt8, UniChar},
15};
16
17use self::iter::Iter;
18
19use super::{
20    cf_array::CFArrayRef, kCFAllocatorDefault, CFAllocatorRef, CFArray, CFCharacterSetRef,
21    CFComparisonResult, CFData, CFDataRef, CFDictionaryRef, CFIndex, CFLocaleRef, CFOptionFlags,
22    CFTypeID, CFTypeObject,
23};
24
25/// For function parameters only - means string is const.
26pub type ConstStr255Param = *const c_uchar;
27
28/// Pointer to a pascal string.
29pub type StringPtr = *mut c_uchar;
30
31/// A complete Unicode character in UTF-32 format, with values from 0 through 0x10FFFF (excluding the surrogate range 0xD800-0xDFFF and certain disallowed values).
32pub type UTF32Char = u32;
33
34pub mod iter;
35
36#[derive(Debug)]
37#[repr(C)]
38pub struct __CFString(c_void);
39
40/// A reference to a CFString object.
41pub type CFStringRef = *const __CFString;
42
43/// An integer type for constants used to specify supported string encodings in various CFString functions.
44pub type CFStringEncoding = u32;
45
46const KCF_STRING_INLINE_BUFFER_LENGTH: usize = 64;
47
48bitflags! {
49    /// An integer type for constants used to specify supported string encodings in various CFString functions.
50    pub struct KCFStringEncoding: CFStringEncoding {
51        /// An encoding constant that identifies the Mac Roman encoding.
52        const MAC_ROMAN = 0;
53        /// An encoding constant that identifies the Windows Latin 1 encoding (ANSI codepage 1252).
54        const WINDOWS_LATIN1 = 0x0500;
55        /// An encoding constant that identifies the ISO Latin 1 encoding (ISO 8859-1)
56        const ISOLATIN1 = 0x0201;
57        /// An encoding constant that identifies the NextStep/OpenStep encoding.
58        const NEXT_STEP_LATIN = 0x0B01;
59        /// An encoding constant that identifies the ASCII encoding (decimal values 0 through 127).
60        const ASCII = 0x0600;
61        /// An encoding constant that identifies the Unicode encoding.
62        const UNICODE = 0x0100;
63        /// An encoding constant that identifies the UTF 8 encoding.
64        const UTF8 = 0x08000100;
65        /// An encoding constant that identifies non-lossy ASCII encoding.
66        const NON_LOSSY_ASCII = 0x0BFF;
67        /// An encoding constant that identifies kTextEncodingUnicodeDefault + kUnicodeUTF16Format encoding (alias of Unicode).
68        const UTF16 = 0x0100;
69        /// An encoding constant that identifies kTextEncodingUnicodeDefault + kUnicodeUTF16BEFormat encoding. This constant specifies big-endian byte order.
70        const UTF16BE = 0x10000100;
71        /// An encoding constant that identifies kTextEncodingUnicodeDefault + kUnicodeUTF16LEFormat encoding. This constant specifies little-endian byte order.
72        const UTF16LE = 0x14000100;
73        /// An encoding constant that identifies kTextEncodingUnicodeDefault + kUnicodeUTF32Format encoding.
74        const UTF32 = 0x0c000100;
75        /// An encoding constant that identifies kTextEncodingUnicodeDefault + kUnicodeUTF32BEFormat encoding. This constant specifies big-endian byte order.
76        const UTF32BE = 0x18000100;
77        /// An encoding constant that identifies kTextEncodingUnicodeDefault + kUnicodeUTF32LEFormat encoding. This constant specifies little-endian byte order.
78        const UTF32LE = 0x1c000100;
79
80        const MAC_JAPANESE = 1;
81        const MAC_CHINESE_TRAD = 2;
82        const MAC_KOREAN = 3;
83        const MAC_ARABIC = 4;
84        const MAC_HEBREW = 5;
85        const MAC_GREEK = 6;
86        const MAC_CYRILLIC = 7;
87        const MAC_DEVANAGARI = 9;
88        const MAC_GURMUKHI = 10;
89        const MAC_GUJARATI = 11;
90        const MAC_ORIYA = 12;
91        const MAC_BENGALI = 13;
92        const MAC_TAMIL = 14;
93        const MAC_TELUGU = 15;
94        const MAC_KANNADA = 16;
95        const MAC_MALAYALAM = 17;
96        const MAC_SINHALESE = 18;
97        const MAC_BURMESE = 19;
98        const MAC_KHMER = 20;
99        const MAC_THAI = 21;
100        const MAC_LAOTIAN = 22;
101        const MAC_GEORGIAN = 23;
102        const MAC_ARMENIAN = 24;
103        const MAC_CHINESE_SIMP = 25;
104        const MAC_TIBETAN = 26;
105        const MAC_MONGOLIAN = 27;
106        const MAC_ETHIOPIC = 28;
107        const MAC_CENTRAL_EUR_ROMAN = 29;
108        const MAC_VIETNAMESE = 30;
109        const MAC_EXT_ARABIC = 31;
110        /* The following use script code 0, smRoman */
111        const MAC_SYMBOL = 33;
112        const MAC_DINGBATS = 34;
113        const MAC_TURKISH = 35;
114        const MAC_CROATIAN = 36;
115        const MAC_ICELANDIC = 37;
116        const MAC_ROMANIAN = 38;
117        const MAC_CELTIC = 39;
118        const MAC_GAELIC = 40;
119        /* The following use script code 4, smArabic */
120        const MAC_FARSI = 0x8C;	/* Like MacArabic but uses Farsi digits */
121        /* The following use script code 7, smCyrillic */
122        const MAC_UKRAINIAN = 0x98;
123        /* The following use script code 32, smUnimplemented */
124        const MAC_INUIT = 0xEC;
125        const MAC_VT100 = 0xFC;	/* VT100/102 font from Comm Toolbox: Latin-1 repertoire + box drawing etc */
126        /* Special Mac OS encodings*/
127        const MAC_HFS = 0xFF;	/* Meta-value, should never appear in a table */
128
129        /* Unicode & ISO UCS encodings begin at 0x100 */
130
131        /* ISO 8-bit and 7-bit encodings begin at 0x200 */
132        const ISO_LATIN2 = 0x0202;	/* ISO 8859-2 */
133        const ISO_LATIN3 = 0x0203;	/* ISO 8859-3 */
134        const ISO_LATIN4 = 0x0204;	/* ISO 8859-4 */
135        const ISO_LATIN_CYRILLIC = 0x0205;	/* ISO 8859-5 */
136        const ISO_LATIN_ARABIC = 0x0206;	/* ISO 8859-6, =ASMO 708, =DOS CP 708 */
137        const ISO_LATIN_GREEK = 0x0207;	/* ISO 8859-7 */
138        const ISO_LATIN_HEBREW = 0x0208;	/* ISO 8859-8 */
139        const ISO_LATIN5 = 0x0209;	/* ISO 8859-9 */
140        const ISO_LATIN6 = 0x020A;	/* ISO 8859-10 */
141        const ISO_LATIN_THAI = 0x020B;	/* ISO 8859-11 */
142        const ISO_LATIN7 = 0x020D;	/* ISO 8859-13 */
143        const ISO_LATIN8 = 0x020E;	/* ISO 8859-14 */
144        const ISO_LATIN9 = 0x020F;	/* ISO 8859-15 */
145        const ISO_LATIN10 = 0x0210;	/* ISO 8859-16 */
146
147        /* MS-DOS & Windows encodings begin at 0x400 */
148        const DOS_LATIN_US = 0x0400;	/* code page 437 */
149        const DOS_GREEK = 0x0405;		/* code page 737 (formerly code page 437G) */
150        const DOS_BALTIC_RIM = 0x0406;	/* code page 775 */
151        const DOS_LATIN1 = 0x0410;	/* code page 850, "Multilingual" */
152        const DOS_GREEK1 = 0x0411;	/* code page 851 */
153        const DOS_LATIN2 = 0x0412;	/* code page 852, Slavic */
154        const DOS_CYRILLIC = 0x0413;	/* code page 855, IBM Cyrillic */
155        const DOS_TURKISH = 0x0414;	/* code page 857, IBM Turkish */
156        const DOS_PORTUGUESE = 0x0415;	/* code page 860 */
157        const DOS_ICELANDIC = 0x0416;	/* code page 861 */
158        const DOS_HEBREW = 0x0417;	/* code page 862 */
159        const DOS_CANADIAN_FRENCH = 0x0418; /* code page 863 */
160        const DOS_ARABIC = 0x0419;	/* code page 864 */
161        const DOS_NORDIC = 0x041A;	/* code page 865 */
162        const DOS_RUSSIAN = 0x041B;	/* code page 866 */
163        const DOS_GREEK2 = 0x041C;	/* code page 869, IBM Modern Greek */
164        const DOS_THAI = 0x041D;		/* code page 874, also for Windows */
165        const DOS_JAPANESE = 0x0420;	/* code page 932, also for Windows */
166        const DOS_CHINESE_SIMPLIFF = 0x0421; /* code page 936, also for Windows */
167        const DOS_KOREAN = 0x0422;	/* code page 949, also for Windows; Unified Hangul Code */
168        const DOS_CHINESE_TRAD = 0x0423;	/* code page 950, also for Windows */
169        const WINDOWS_LATIN2 = 0x0501;	/* code page 1250, Central Europe */
170        const WINDOWS_CYRILLIC = 0x0502;	/* code page 1251, Slavic Cyrillic */
171        const WINDOWS_GREEK = 0x0503;	/* code page 1253 */
172        const WINDOWS_LATIN5 = 0x0504;	/* code page 1254, Turkish */
173        const WINDOWS_HEBREW = 0x0505;	/* code page 1255 */
174        const WINDOWS_ARABICC = 0x0506;	/* code page 1256 */
175        const WINDOWS_BALTIC_RIM = 0x0507;	/* code page 1257 */
176        const WINDOWS_VIETNAMESE = 0x0508; /* code page 1258 */
177        const WINDOWS_KOREAN_JOHAB = 0x0510; /* code page 1361, for Windows NT */
178
179        /* Various national standards begin at 0x600 */
180        const ANSEL = 0x0601;	/* ANSEL (ANSI Z39.47) */
181        const JIS_X0201_76 = 0x0620;
182        const JIS_X0208_83 = 0x0621;
183        const JIS_X0208_90 = 0x0622;
184        const JIS_X0212_90 = 0x0623;
185        const JIS_C6226_78 = 0x0624;
186        const SHIFT_JIS_X0213 = 0x0628; /* Shift-JIS format encoding of JIS X0213 planes 1 and 2*/
187        const SHIFT_JIS_X0213_MEN_KU_TEN = 0x0629;	/* JIS X0213 in plane-row-column notation */
188        const GB_2312_80 = 0x0630;
189        const GBK_95 = 0x0631;		/* annex to GB 13000-93; for Windows 95 */
190        const GB_18030_2000 = 0x0632;
191        const KSC_5601_87 = 0x0640;	/* same as KSC 5601-92 without Johab annex */
192        const KSC_5601_92_JOHAB = 0x0641; /* KSC 5601-92 Johab annex */
193        const CNS_11643_92_P1 = 0x0651;	/* CNS 11643-1992 plane 1 */
194        const CNS_11643_92_P2 = 0x0652;	/* CNS 11643-1992 plane 2 */
195        const CNS_11643_92_P3 = 0x0653;	/* CNS 11643-1992 plane 3 (was plane 14 in 1986 version) */
196
197        /* ISO 2022 collections begin at 0x800 */
198        const ISO_2022_JP = 0x0820;
199        const ISO_2022_JP_2 = 0x0821;
200        const ISO_2022_JP_1 = 0x0822; /* RFC 2237*/
201        const ISO_2022_JP_3 = 0x0823; /* JIS X0213*/
202        const ISO_2022_CN = 0x0830;
203        const ISO_2022_CN_EXT = 0x0831;
204        const ISO_2022_KR = 0x0840;
205
206        /* EUC collections begin at 0x900 */
207        const EUC_JP = 0x0920;		/* ISO 646, 1-byte katakana, JIS 208, JIS 212 */
208        const EUC_CN = 0x0930;		/* ISO 646, GB 2312-80 */
209        const EUC_TW = 0x0931;		/* ISO 646, CNS 11643-1992 Planes 1-16 */
210        const EUC_KR = 0x0940;		/* ISO 646, KS C 5601-1987 */
211
212        /* Misc standards begin at 0xA00 */
213        const SHIFT_JIS = 0x0A01;		/* plain Shift-JIS */
214        const KOI8_R = 0x0A02;		/* Russian internet standard */
215        const BIG5 = 0x0A03;		/* Big-5 (has variants) */
216        const MAC_ROMAN_LATIN1 = 0x0A04;	/* Mac OS Roman permuted to align with ISO Latin-1 */
217        const HZ_GB_2312 = 0x0A05;	/* HZ (RFC 1842, for Chinese mail & news) */
218        const BIG5_HKSCS_1999 = 0x0A06; /* Big-5 with Hong Kong special char set supplement*/
219        const VISCII = 0x0A07;	/* RFC 1456, Vietnamese */
220        const KOI8_U = 0x0A08;	/* RFC 2319, Ukrainian */
221        const BIG5_E = 0x0A09;	/* Taiwan Big-5E standard */
222
223        /* Other platform encodings*/
224        const NEXT_STEP_JAPANESE = 0x0B02;	/* NextStep Japanese encoding */
225
226        /* EBCDIC & IBM host encodings begin at 0xC00 */
227        const EBCDIC_US = 0x0C01;	/* basic EBCDIC-US */
228        const EBCDIC_CP037 = 0x0C02;	/* code page 037, extended EBCDIC (Latin-1 set) for US,Canada... */
229
230        const UTF7 = 0x04000100; /* kTextEncodingUnicodeDefault + kUnicodeUTF7Format RFC2152 */
231        const UTF7_IMAP = 0x0A10; /* UTF-7 (IMAP folder variant) RFC3501 */
232
233        /* Deprecated constants */
234        #[deprecated]
235        const SHIFT_JIS_X0213_00 = 0x0628; /* Shift-JIS format encoding of JIS X0213 planes 1 and 2 (DEPRECATED) */
236    }
237}
238
239bitflags! {
240    /// A [`CFOptionFlags`] type for specifying options for string comparison .
241    pub struct CFStringCompareFlags: CFOptionFlags {
242        const DEFAULT = 0;
243        /// Specifies that the comparison should ignore differences in case between alphabetical characters.
244        const CASE_INSENSITIVE = 1;
245        /// Specifies that the comparison should start at the last elements of the entities being compared (for example, strings or arrays).
246        const BACKWARDS = 4;
247        /// Performs searching only on characters at the beginning or end of the range.
248        const ANCHORED = 8;
249        /// Specifies that loose equivalence is acceptable, especially as pertains to diacritical marks.
250        const NONLITERAL = 16;
251        /// Specifies that the comparison should take into account differences related to locale, such as the thousands separator character.
252        const LOCALIZED = 32;
253        /// Specifies that represented numeric values should be used as the basis for comparison and not the actual character values.
254        const NUMERICALLY = 64;
255        /// Specifies that the comparison should ignore diacritic markers.
256        const DIACRITIC_INSENSITIVE  = 128;
257        /// Specifies that the comparison should ignore width differences.
258        const WIDTH_INSENSITIVE  = 256;
259        /// Specifies that the comparison is forced to return either [`super::CFComparisonResult::KCFCompareLessThan`] or [`super::CFComparisonResult::KCFCompareGreaterThan`] if the strings are equivalent but not strictly equal.
260        const FORCED_ORDERING  = 512;
261    }
262}
263
264declare_CFType! {
265    /// A reference to a CFString object.
266    #[repr(C)]
267    CFString, CFStringRef
268}
269
270/// Defines the buffer and related fields used for in-line buffer access of characters in CFString objects.
271#[derive(Debug)]
272#[repr(C)]
273pub struct CFStringInlineBuffer {
274    pub buffer: [UniChar; KCF_STRING_INLINE_BUFFER_LENGTH],
275    pub string: CFStringRef,
276    pub direct_unichar_buffer: *const UniChar,
277    pub direct_c_string_buffer: *const c_char,
278    /// Range in string to buffer
279    pub range_to_buffer: CFRange,
280    /// Start of range currently buffered (relative to rangeToBuffer.location)
281    pub buffered_range_start: CFIndex,
282    /// bufferedRangeStart + number of chars actually buffered
283    pub buffered_range_end: CFIndex,
284}
285
286impl CFString {
287    /// Creates a new [`CFStringRef`]
288    pub fn with_str(s: &str) -> Self {
289        unsafe {
290            let cstr = CStr::from_ptr(s.as_ptr() as *const i8);
291
292            Self(CFStringCreateWithBytes(
293                kCFAllocatorDefault,
294                cstr.as_ptr() as *const u8,
295                s.len() as CFIndex,
296                0,
297                false,
298            ))
299        }
300    }
301
302    /// Creates an iterator.
303    pub fn iter(&self) -> Iter<'_> {
304        Iter {
305            string: self,
306            index: 0,
307        }
308    }
309
310    /* Creating a CFString
311     */
312
313    /// Creates an array of CFString objects from a single CFString object.
314    ///
315    /// # Safety
316    ///
317    /// This function dereferences a raw pointer
318    pub unsafe fn create_array_by_separating_strings(
319        alloc: CFAllocatorRef,
320        string: CFStringRef,
321        separator: CFStringRef,
322    ) -> CFArray {
323        CFArray::create_with_ref(CFStringCreateArrayBySeparatingStrings(
324            alloc, string, separator,
325        ))
326    }
327
328    /// Creates a single string from the individual CFString objects that comprise the elements of an array.
329    ///
330    /// # Safety
331    ///
332    /// This function dereferences a raw pointer
333    pub unsafe fn create_by_combining_strings(
334        alloc: CFAllocatorRef,
335        array: CFArrayRef,
336        separator: CFStringRef,
337    ) -> CFString {
338        CFString::create_with_ref(CFStringCreateByCombiningStrings(alloc, array, separator))
339    }
340
341    /// Creates an immutable copy of a string.
342    ///
343    /// # Safety
344    ///
345    /// This function dereferences a raw pointer
346    pub unsafe fn create_copy(alloc: CFAllocatorRef, string: CFStringRef) -> CFString {
347        CFString::create_with_ref(CFStringCreateCopy(alloc, string))
348    }
349
350    /// Creates a string from its “external representation.”
351    ///
352    /// # Safety
353    ///
354    /// This function dereferences a raw pointer
355    pub unsafe fn create_from_external_representation(
356        alloc: CFAllocatorRef,
357        data: CFDataRef,
358        encoding: CFStringEncoding,
359    ) -> CFString {
360        CFString::create_with_ref(CFStringCreateFromExternalRepresentation(
361            alloc, data, encoding,
362        ))
363    }
364
365    /// Creates a string from a buffer containing characters in a specified encoding.
366    ///
367    /// # Safety
368    ///
369    /// This function dereferences a raw pointer
370    pub unsafe fn create_with_bytes(
371        alloc: CFAllocatorRef,
372        bytes: *const UInt8,
373        num_bytes: CFIndex,
374        encoding: CFStringEncoding,
375        is_external_representation: bool,
376    ) -> Self {
377        Self::create_with_ref(CFStringCreateWithBytes(
378            alloc,
379            bytes,
380            num_bytes,
381            encoding,
382            is_external_representation,
383        ))
384    }
385
386    /// Creates a string from a buffer, containing characters in a specified encoding, that might serve as the backing store for the new string.
387    ///
388    /// # Safety
389    ///
390    /// This function dereferences a raw pointer
391    pub unsafe fn create_with_bytes_no_copy(
392        alloc: CFAllocatorRef,
393        bytes: *const UInt8,
394        num_bytes: CFIndex,
395        encoding: CFStringEncoding,
396        is_external_representation: Boolean,
397        contents_deallocator: CFAllocatorRef,
398    ) -> CFString {
399        CFString::create_with_ref(CFStringCreateWithBytesNoCopy(
400            alloc,
401            bytes,
402            num_bytes,
403            encoding,
404            is_external_representation,
405            contents_deallocator,
406        ))
407    }
408
409    /// Creates a string from a buffer of Unicode characters.
410    ///
411    /// # Safety
412    ///
413    /// This function dereferences a raw pointer
414    pub unsafe fn create_with_characters(
415        alloc: CFAllocatorRef,
416        chars: *const UniChar,
417        num_chars: CFIndex,
418    ) -> CFString {
419        CFString::create_with_ref(CFStringCreateWithCharacters(alloc, chars, num_chars))
420    }
421
422    /// Creates a string from a buffer of Unicode characters that might serve as the backing store for the object.
423    ///
424    /// # Safety
425    ///
426    /// This function dereferences a raw pointer
427    pub unsafe fn create_with_characters_no_copy(
428        alloc: CFAllocatorRef,
429        chars: *const UniChar,
430        num_chars: CFIndex,
431        contents_deallocator: CFAllocatorRef,
432    ) -> CFString {
433        CFString::create_with_ref(CFStringCreateWithCharactersNoCopy(
434            alloc,
435            chars,
436            num_chars,
437            contents_deallocator,
438        ))
439    }
440
441    /// Creates an immutable string from a C string.
442    ///
443    /// # Safety
444    ///
445    /// This function dereferences a raw pointer
446    pub unsafe fn create_with_c_string(
447        alloc: CFAllocatorRef,
448        c_str: *const c_char,
449        encoding: CFStringEncoding,
450    ) -> CFString {
451        CFString::create_with_ref(CFStringCreateWithCString(alloc, c_str, encoding))
452    }
453
454    /// Creates a CFString object from an external C string buffer that might serve as the backing store for the object.
455    ///
456    /// # Safety
457    ///
458    /// This function dereferences a raw pointer
459    pub unsafe fn create_with_c_string_no_copy(
460        alloc: CFAllocatorRef,
461        c_str: *const c_char,
462        encoding: CFStringEncoding,
463        contents_deallocator: CFAllocatorRef,
464    ) -> CFString {
465        CFString::create_with_ref(CFStringCreateWithCStringNoCopy(
466            alloc,
467            c_str,
468            encoding,
469            contents_deallocator,
470        ))
471    }
472
473    /// Creates an immutable string from a formatted string and a variable number of arguments (specified in a parameter of type va_list).
474    ///
475    /// # Safety
476    ///
477    /// This function dereferences a raw pointer
478    pub unsafe fn create_with_format_and_arguments(
479        alloc: CFAllocatorRef,
480        format_options: CFDictionaryRef,
481        format: CFStringRef,
482        va_list: va_list::VaList,
483    ) -> CFString {
484        CFString::create_with_ref(CFStringCreateWithFormatAndArguments(
485            alloc,
486            format_options,
487            format,
488            va_list,
489        ))
490    }
491
492    /// Creates an immutable CFString object from a Pascal string.
493    ///
494    /// # Safety
495    ///
496    /// This function dereferences a raw pointer
497    pub unsafe fn create_with_pascal_string(
498        alloc: CFAllocatorRef,
499        p_str: ConstStr255Param,
500        encoding: CFStringEncoding,
501    ) -> CFString {
502        CFString::create_with_ref(CFStringCreateWithPascalString(alloc, p_str, encoding))
503    }
504
505    /// Creates a CFString object from an external Pascal string buffer that might serve as the backing store for the object.
506    ///
507    /// # Safety
508    ///
509    /// This function dereferences a raw pointer
510    pub unsafe fn create_with_pascal_string_no_copy(
511        alloc: CFAllocatorRef,
512        p_str: ConstStr255Param,
513        encoding: CFStringEncoding,
514        contents_deallocator: CFAllocatorRef,
515    ) -> CFString {
516        CFString::create_with_ref(CFStringCreateWithPascalStringNoCopy(
517            alloc,
518            p_str,
519            encoding,
520            contents_deallocator,
521        ))
522    }
523
524    /// Creates an immutable string from a segment (substring) of an existing string.
525    ///
526    /// # Safety
527    ///
528    /// This function dereferences a raw pointer
529    pub unsafe fn create_with_substring(
530        alloc: CFAllocatorRef,
531        s: CFStringRef,
532        range: CFRange,
533    ) -> CFString {
534        CFString::create_with_ref(CFStringCreateWithSubstring(alloc, s, range))
535    }
536
537    /* Searching Strings
538     */
539
540    /// Searches a string for multiple occurrences of a substring and creates an array of ranges identifying the locations of these substrings within the target string.
541    ///
542    /// # Safety
543    ///
544    /// This function dereferences a raw pointer
545    pub unsafe fn create_array_with_find_results(
546        alloc: CFAllocatorRef,
547        string: CFStringRef,
548        string_to_find: CFStringRef,
549        range_to_search: CFRange,
550        compare_options: CFStringCompareFlags,
551    ) -> CFArray {
552        CFArray::create_with_ref(CFStringCreateArrayWithFindResults(
553            alloc,
554            string,
555            string_to_find,
556            range_to_search,
557            compare_options,
558        ))
559    }
560
561    /// Searches for a substring within a string and, if it is found, yields the range of the substring within the object's characters.
562    ///
563    /// # Safety
564    ///
565    /// This function dereferences a raw pointer
566    pub unsafe fn find(
567        string: CFStringRef,
568        string_to_find: CFStringRef,
569        compare_options: CFStringCompareFlags,
570    ) -> CFRange {
571        CFStringFind(string, string_to_find, compare_options)
572    }
573
574    /// Query the range of the first character contained in the specified character set.
575    ///
576    /// # Safety
577    ///
578    /// This function dereferences a raw pointer
579    pub unsafe fn find_character_from_set(
580        string: CFStringRef,
581        set: CFCharacterSetRef,
582        range_to_search: CFRange,
583        search_options: CFStringCompareFlags,
584        result: *mut CFRange,
585    ) -> bool {
586        CFStringFindCharacterFromSet(string, set, range_to_search, search_options, result)
587    }
588
589    /// Searches for a substring within a range of the characters represented by a string and, if the substring is found, returns its range within the object's characters.
590    ///
591    /// # Safety
592    ///
593    /// This function dereferences a raw pointer
594    pub unsafe fn find_with_options(
595        string: CFStringRef,
596        string_to_find: CFStringRef,
597        range_to_search: CFRange,
598        search_options: CFStringCompareFlags,
599        result: *mut CFRange,
600    ) -> bool {
601        CFStringFindWithOptions(
602            string,
603            string_to_find,
604            range_to_search,
605            search_options,
606            result,
607        )
608    }
609
610    /// Returns a Boolean value that indicates whether a given string was found in a given source string.
611    ///
612    /// # Safety
613    ///
614    /// This function dereferences a raw pointer
615    pub unsafe fn find_with_options_and_locale(
616        string: CFStringRef,
617        string_to_find: CFStringRef,
618        range_to_search: CFRange,
619        search_options: CFStringCompareFlags,
620        locale: CFLocaleRef,
621        result: *mut CFRange,
622    ) -> bool {
623        CFStringFindWithOptionsAndLocale(
624            string,
625            string_to_find,
626            range_to_search,
627            search_options,
628            locale,
629            result,
630        )
631    }
632
633    /// Given a range of characters in a string, obtains the line bounds—that is, the indexes of the first character and the final characters of the lines containing the range.
634    ///
635    /// # Safety
636    ///
637    /// This function dereferences a raw pointer
638    pub unsafe fn get_line_bounds(
639        string: CFStringRef,
640        range: CFRange,
641        line_begin_index: *mut CFIndex,
642        line_end_index: *mut CFIndex,
643        contents_end_index: *mut CFIndex,
644    ) {
645        CFStringGetLineBounds(
646            string,
647            range,
648            line_begin_index,
649            line_end_index,
650            contents_end_index,
651        )
652    }
653
654    /* Comparing Strings
655     */
656
657    /// Compares one string with another string.
658    ///
659    /// # Safety
660    ///
661    /// This function dereferences a raw pointer
662    pub unsafe fn compare(
663        string1: CFStringRef,
664        string2: CFStringRef,
665        compare_options: CFStringCompareFlags,
666    ) -> CFComparisonResult {
667        CFStringCompare(string1, string2, compare_options)
668    }
669
670    /// Compares a range of the characters in one string with that of another string.
671    ///
672    /// # Safety
673    ///
674    /// This function dereferences a raw pointer
675    pub unsafe fn compare_with_options(
676        string1: CFStringRef,
677        string2: CFStringRef,
678        range_to_compare: CFRange,
679        compare_options: CFStringCompareFlags,
680    ) -> CFComparisonResult {
681        CFStringCompareWithOptions(string1, string2, range_to_compare, compare_options)
682    }
683
684    /// Compares a range of the characters in one string with another string using a given locale.
685    ///
686    /// # Safety
687    ///
688    /// This function dereferences a raw pointer
689    pub unsafe fn compare_with_options_and_locale(
690        string1: CFStringRef,
691        string2: CFStringRef,
692        range_to_compare: CFRange,
693        compare_options: CFStringCompareFlags,
694        locale: CFLocaleRef,
695    ) -> CFComparisonResult {
696        CFStringCompareWithOptionsAndLocale(
697            string1,
698            string2,
699            range_to_compare,
700            compare_options,
701            locale,
702        )
703    }
704
705    /// Determines if the character data of a string begin with a specified sequence of characters.
706    ///
707    /// # Safety
708    ///
709    /// This function dereferences a raw pointer
710    pub unsafe fn has_prefix(string: CFStringRef, prefix: CFStringRef) -> bool {
711        CFStringHasPrefix(string, prefix)
712    }
713
714    ///Determines if a string ends with a specified sequence of characters.
715    ///
716    /// # Safety
717    ///
718    /// This function dereferences a raw pointer
719    pub unsafe fn has_suffix(string: CFStringRef, suffix: CFStringRef) -> bool {
720        CFStringHasSuffix(string, suffix)
721    }
722
723    /* Accessing Characters
724     */
725
726    /// Creates an “external representation” of a CFString object, that is, a CFData object.
727    ///
728    /// # Safety
729    ///
730    /// This function dereferences a raw pointer
731    pub unsafe fn create_external_representation(
732        alloc: CFStringRef,
733        string: CFStringEncoding,
734        encoding: CFStringEncoding,
735        loss_byte: UInt8,
736    ) -> CFData {
737        CFData::create_with_ref(CFStringCreateExternalRepresentation(
738            alloc, string, encoding, loss_byte,
739        ))
740    }
741
742    /// Fetches a range of the characters from a string into a byte buffer after converting the characters to a specified encoding.
743    ///
744    /// # Safety
745    ///
746    /// This function dereferences a raw pointer
747    #[allow(clippy::too_many_arguments)]
748    pub unsafe fn get_bytes(
749        string: CFStringRef,
750        range: CFRange,
751        encoding: CFStringEncoding,
752        loss_byte: UInt8,
753        is_external_representation: Boolean,
754        buffer: *mut UInt8,
755        max_buf_len: CFIndex,
756        used_buf_len: *mut CFIndex,
757    ) -> CFIndex {
758        CFStringGetBytes(
759            string,
760            range,
761            encoding,
762            loss_byte,
763            is_external_representation,
764            buffer,
765            max_buf_len,
766            used_buf_len,
767        )
768    }
769
770    /// Returns the Unicode character at a specified location in a string.
771    ///
772    /// # Safety
773    ///
774    /// This function dereferences a raw pointer
775    pub unsafe fn get_character_at_index(string: CFStringRef, idx: CFIndex) -> UniChar {
776        CFStringGetCharacterAtIndex(string, idx)
777    }
778
779    /// Copies a range of the Unicode characters from a string to a user-provided buffer.
780    ///
781    /// # Safety
782    ///
783    /// This function dereferences a raw pointer
784    pub unsafe fn get_characters(string: CFStringRef, range: CFRange, buffer: &mut [UniChar]) {
785        CFStringGetCharacters(string, range, buffer)
786    }
787
788    /// Quickly obtains a pointer to the contents of a string as a buffer of Unicode characters.
789    ///
790    /// # Safety
791    ///
792    /// This function dereferences a raw pointer
793    pub unsafe fn get_characters_ptr(string: CFStringRef) -> *const UniChar {
794        CFStringGetCharactersPtr(string)
795    }
796
797    /// Returns the Unicode character at a specific location in an in-line buffer.
798    ///
799    /// # Safety
800    ///
801    /// This function dereferences a raw pointer
802    pub unsafe fn get_character_from_inline_buffer(
803        buf: *mut CFStringInlineBuffer,
804        idx: CFIndex,
805    ) -> UniChar {
806        CFStringGetCharacterFromInlineBuffer(buf, idx)
807    }
808
809    /// Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding.
810    ///
811    /// # Safety
812    ///
813    /// This function dereferences a raw pointer
814    pub unsafe fn get_c_string(
815        string: CFStringRef,
816        buffer: &mut [c_char],
817        buffer_size: CFIndex,
818        encoding: CFStringEncoding,
819    ) -> bool {
820        CFStringGetCString(string, buffer, buffer_size, encoding)
821    }
822
823    /// Quickly obtains a pointer to a C-string buffer containing the characters of a string in a given encoding.
824    ///
825    /// # Safety
826    ///
827    /// This function dereferences a raw pointer
828    pub unsafe fn get_c_string_ptr(
829        string: CFStringRef,
830        encoding: CFStringEncoding,
831    ) -> *const c_char {
832        CFStringGetCStringPtr(string, encoding)
833    }
834
835    /// Returns the number (in terms of UTF-16 code pairs) of Unicode characters in a string.
836    ///
837    /// # Safety
838    ///
839    /// This function dereferences a raw pointer
840    pub unsafe fn get_length(string: CFStringRef) -> CFIndex {
841        CFStringGetLength(string)
842    }
843
844    /// Copies the character contents of a [`CFString`] object to a local Pascal string buffer after converting the characters to a requested encoding.
845    ///
846    /// # Safety
847    ///
848    /// This function dereferences a raw pointer
849    pub unsafe fn get_pascal_string(
850        string: CFStringRef,
851        buffer: StringPtr,
852        buffer_size: CFIndex,
853        encoding: CFStringEncoding,
854    ) -> bool {
855        CFStringGetPascalString(string, buffer, buffer_size, encoding)
856    }
857
858    /// Quickly obtains a pointer to a Pascal buffer containing the characters of a string in a given encoding.
859    ///
860    /// # Safety
861    ///
862    /// This function dereferences a raw pointer
863    pub unsafe fn get_pascal_string_ptr(
864        string: CFStringRef,
865        encoding: CFStringEncoding,
866    ) -> ConstStr255Param {
867        CFStringGetPascalStringPtr(string, encoding)
868    }
869
870    /// Returns the range of the composed character sequence at a specified index.
871    ///
872    /// # Safety
873    ///
874    /// This function dereferences a raw pointer
875    pub unsafe fn get_range_of_composed_characters_at_index(
876        string: CFStringRef,
877        index: CFIndex,
878    ) -> CFRange {
879        CFStringGetRangeOfComposedCharactersAtIndex(string, index)
880    }
881
882    /// Initializes an in-line buffer to use for efficient access of a [`CFString`] object's characters.
883    ///
884    /// # Safety
885    ///
886    /// This function dereferences a raw pointer
887    pub unsafe fn init_inline_buffer(
888        s: CFStringRef,
889        buf: *mut CFStringInlineBuffer,
890        range: CFRange,
891    ) {
892        CFStringInitInlineBuffer(s, buf, range)
893    }
894
895    /* Working With Hyphenation
896     */
897
898    /// Retrieve the first potential hyphenation location found before the specified location.
899    ///
900    /// # Safety
901    ///
902    /// This function dereferences a raw pointer
903    pub unsafe fn get_hyphenation_location_before_index(
904        string: CFStringRef,
905        location: CFIndex,
906        limit_range: CFRange,
907        options: CFOptionFlags,
908        locale: CFLocaleRef,
909        character: *mut UTF32Char,
910    ) -> CFIndex {
911        CFStringGetHyphenationLocationBeforeIndex(
912            string,
913            location,
914            limit_range,
915            options,
916            locale,
917            character,
918        )
919    }
920
921    /// Returns a [`Boolean`] value that indicates whether hyphenation data is available.
922    ///
923    /// # Safety
924    ///
925    /// This function dereferences a raw pointer
926    pub unsafe fn is_hyphenation_available_for_locale(locale: CFLocaleRef) -> Boolean {
927        CFStringIsHyphenationAvailableForLocale(locale)
928    }
929
930    /* Working With Encodings
931     */
932
933    /// Returns the name of the IANA registry “charset” that is the closest mapping to a specified string encoding.
934    ///
935    /// # Safety
936    ///
937    /// This function dereferences a raw pointer
938    pub unsafe fn convert_encoding_to_ianachar_set_name(encoding: CFStringEncoding) -> CFString {
939        CFString::create_with_ref(CFStringConvertEncodingToIANACharSetName(encoding))
940    }
941
942    /// Returns the Cocoa encoding constant that maps most closely to a given Core Foundation encoding constant.
943    ///
944    /// # Safety
945    ///
946    /// This function dereferences a raw pointer
947    pub unsafe fn convert_encoding_to_nsstring_encoding(encoding: CFStringEncoding) -> c_ulong {
948        CFStringConvertEncodingToNSStringEncoding(encoding)
949    }
950
951    /// Returns the Windows codepage identifier that maps most closely to a given Core Foundation encoding constant.
952    ///
953    /// # Safety
954    ///
955    /// This function dereferences a raw pointer
956    pub unsafe fn convert_encoding_to_windows_codepage(encoding: CFStringEncoding) -> UInt32 {
957        CFStringConvertEncodingToWindowsCodepage(encoding)
958    }
959
960    /// Returns the Core Foundation encoding constant that is the closest mapping to a given IANA registry “charset” name.
961    ///
962    /// # Safety
963    ///
964    /// This function dereferences a raw pointer
965    pub unsafe fn convert_iana_char_set_name_to_encodingng(
966        string: CFStringRef,
967    ) -> CFStringEncoding {
968        CFStringConvertIANACharSetNameToEncoding(string)
969    }
970
971    /// Returns the Core Foundation encoding constant that is the closest mapping to a given Cocoa encoding.
972    ///
973    /// # Safety
974    ///
975    /// This function dereferences a raw pointer
976    pub unsafe fn convert_nsstring_encoding_to_encodingng(encoding: c_ulong) -> CFStringEncoding {
977        CFStringConvertNSStringEncodingToEncoding(encoding)
978    }
979
980    /// Returns the Core Foundation encoding constant that is the closest mapping to a given Windows codepage identifier.
981    ///
982    /// # Safety
983    ///
984    /// This function dereferences a raw pointer
985    pub unsafe fn convert_windows_codepage_to_encoding(codepage: UInt32) -> CFStringEncoding {
986        CFStringConvertWindowsCodepageToEncoding(codepage)
987    }
988
989    /// Returns for a [`CFString`] object the character encoding that requires the least conversion time.
990    ///
991    /// # Safety
992    ///
993    /// This function dereferences a raw pointer
994    pub unsafe fn get_fastest_encoding(string: CFStringRef) -> CFStringEncoding {
995        CFStringGetFastestEncoding(string)
996    }
997
998    /// Returns a pointer to a list of string encodings supported by the current system.
999    ///
1000    /// # Safety
1001    ///
1002    /// This function dereferences a raw pointer
1003    pub unsafe fn get_list_of_available_encodings() -> *const CFStringEncoding {
1004        CFStringGetListOfAvailableEncodings()
1005    }
1006
1007    /// Returns the maximum number of bytes a string of a specified length (in Unicode characters) will take up if encoded in a specified encoding.
1008    ///
1009    /// # Safety
1010    ///
1011    /// This function dereferences a raw pointer
1012    pub unsafe fn get_maximum_size_for_encoding(
1013        length: CFIndex,
1014        encoding: CFStringEncoding,
1015    ) -> CFIndex {
1016        CFStringGetMaximumSizeForEncoding(length, encoding)
1017    }
1018
1019    /// Returns the most compatible Mac OS script value for the given input encoding.
1020    ///
1021    /// # Safety
1022    ///
1023    /// This function dereferences a raw pointer
1024    pub unsafe fn get_most_compatible_mac_string_encoding(
1025        encoding: CFStringEncoding,
1026    ) -> CFStringEncoding {
1027        CFStringGetMostCompatibleMacStringEncoding(encoding)
1028    }
1029
1030    /// Returns the canonical name of a specified string encoding.
1031    ///
1032    /// # Safety
1033    ///
1034    /// This function dereferences a raw pointer
1035    pub unsafe fn get_name_of_encoding(encoding: CFStringEncoding) -> CFString {
1036        CFString::create_with_ref(CFStringGetNameOfEncoding(encoding))
1037    }
1038
1039    /// Returns the smallest encoding on the current system for the character contents of a string.
1040    ///
1041    /// # Safety
1042    ///
1043    /// This function dereferences a raw pointer
1044    pub unsafe fn get_smallest_encoding(string: CFStringRef) -> CFStringEncoding {
1045        CFStringGetSmallestEncoding(string)
1046    }
1047
1048    /// Returns the default encoding used by the operating system when it creates strings.
1049    ///
1050    /// # Safety
1051    ///
1052    /// This function dereferences a raw pointer
1053    pub unsafe fn get_system_encoding() -> CFStringEncoding {
1054        CFStringGetSystemEncoding()
1055    }
1056
1057    /// Determines whether a given Core Foundation string encoding is available on the current system.
1058    ///
1059    /// # Safety
1060    ///
1061    /// This function dereferences a raw pointer
1062    pub unsafe fn is_encoding_available(encoding: CFStringEncoding) -> bool {
1063        CFStringIsEncodingAvailable(encoding)
1064    }
1065
1066    /* Getting Numeric Values
1067     */
1068
1069    /// Returns the primary [`c_double`] value represented by a string.
1070    ///
1071    /// # Safety
1072    ///
1073    /// This function dereferences a raw pointer
1074    pub unsafe fn get_double_value(s: CFStringRef) -> c_double {
1075        CFStringGetDoubleValue(s)
1076    }
1077
1078    /// Returns the [`SInt32`] value represented by a string.
1079    ///
1080    /// # Safety
1081    ///
1082    /// This function dereferences a raw pointer
1083    pub unsafe fn get_int_value(s: CFStringRef) -> SInt32 {
1084        CFStringGetIntValue(s)
1085    }
1086
1087    /* Getting String Properties
1088     */
1089
1090    /// Prints the attributes of a string during debugging.
1091    ///
1092    /// # Safety
1093    ///
1094    /// This function dereferences a raw pointer
1095    pub unsafe fn cf_show_str(s: CFStringRef) {
1096        CFShowStr(s)
1097    }
1098
1099    /// Returns the type identifier for the [`CFString`] opaque type.
1100    ///
1101    /// # Safety
1102    ///
1103    /// This function dereferences a raw pointer
1104    pub unsafe fn get_type_id() -> CFTypeID {
1105        CFStringGetTypeID()
1106    }
1107
1108    /* String File System Representations
1109     */
1110
1111    /// Creates a [`CFString`] from a zero-terminated POSIX file system representation.
1112    ///
1113    /// # Safety
1114    ///
1115    /// This function dereferences a raw pointer
1116    pub unsafe fn create_with_file_system_representation(
1117        alloc: CFAllocatorRef,
1118        buffer: *const c_char,
1119    ) -> CFString {
1120        CFString::create_with_ref(CFStringCreateWithFileSystemRepresentation(alloc, buffer))
1121    }
1122
1123    /// Extracts the contents of a string as a NULL-terminated 8-bit string appropriate for passing to POSIX APIs.
1124    ///
1125    /// # Safety
1126    ///
1127    /// This function dereferences a raw pointer
1128    pub unsafe fn get_file_system_representation(
1129        string: CFStringRef,
1130        buffer: &mut [c_char],
1131        max_buf_len: CFIndex,
1132    ) -> Boolean {
1133        CFStringGetFileSystemRepresentation(string, buffer, max_buf_len)
1134    }
1135
1136    /// Determines the upper bound on the number of bytes required to hold the file system representation of the string.
1137    ///
1138    /// # Safety
1139    ///
1140    /// This function dereferences a raw pointer
1141    pub unsafe fn get_maximum_size_of_file_system_representation(string: CFStringRef) -> CFIndex {
1142        CFStringGetMaximumSizeOfFileSystemRepresentation(string)
1143    }
1144
1145    /* Getting Paragraph Bounds
1146     */
1147
1148    /// Determines the upper bound on the number of bytes required to hold the file system representation of the string.
1149    ///
1150    /// # Safety
1151    ///
1152    /// This function dereferences a raw pointer
1153    pub unsafe fn get_paragraph_bounds(
1154        string: CFStringRef,
1155        range: CFRange,
1156        par_begin_index: *mut CFIndex,
1157        par_end_index: *mut CFIndex,
1158        contents_end_index: *mut CFIndex,
1159    ) {
1160        CFStringGetParagraphBounds(
1161            string,
1162            range,
1163            par_begin_index,
1164            par_end_index,
1165            contents_end_index,
1166        )
1167    }
1168
1169    /* Managing Surrogates
1170     */
1171
1172    /// Returns a UTF-32 character that corresponds to a given pair of UTF-16 surrogate characters.
1173    ///
1174    /// # Safety
1175    ///
1176    /// This function dereferences a raw pointer
1177    pub unsafe fn get_long_character_for_surrogate_pair(
1178        surrogate_high: UniChar,
1179        surrogate_low: UniChar,
1180    ) -> UTF32Char {
1181        CFStringGetLongCharacterForSurrogatePair(surrogate_high, surrogate_low)
1182    }
1183
1184    /// Maps a given UTF-32 character to a pair of UTF-16 surrogate characters.
1185    ///
1186    /// # Safety
1187    ///
1188    /// This function dereferences a raw pointer
1189    pub unsafe fn get_surrogate_pair_for_long_character(
1190        character: UTF32Char,
1191        surrogates: &mut [UniChar],
1192    ) -> Boolean {
1193        CFStringGetSurrogatePairForLongCharacter(character, surrogates)
1194    }
1195
1196    /// Returns a [`Boolean`] value that indicates whether a given character is a high character in a surrogate pair.
1197    ///
1198    /// # Safety
1199    ///
1200    /// This function dereferences a raw pointer
1201    pub unsafe fn is_surrogate_high_character(character: UniChar) -> Boolean {
1202        CFStringIsSurrogateHighCharacter(character)
1203    }
1204
1205    /// Returns a [`Boolean`] value that indicates whether a given character is a low character in a surrogate pair.
1206    ///
1207    /// # Safety
1208    ///
1209    /// This function dereferences a raw pointer
1210    pub unsafe fn is_surrogate_low_character(character: UniChar) -> Boolean {
1211        CFStringIsSurrogateLowCharacter(character)
1212    }
1213}
1214
1215impl<'a> From<&'a CFString> for Cow<'a, str> {
1216    fn from(cf_str: &'a CFString) -> Cow<'a, str> {
1217        unsafe {
1218            // Do this without allocating if we can get away with it
1219            let c_string =
1220                CFStringGetCStringPtr(cf_str.get_internal_object(), KCFStringEncoding::UTF8.bits);
1221            match c_string.is_null() {
1222                true => {
1223                    let char_len = CFString::get_length(cf_str.get_internal_object());
1224
1225                    // First, ask how big the buffer ought to be.
1226                    let mut bytes_required: CFIndex = 0;
1227                    let _ = CFStringGetBytes(
1228                        cf_str.get_internal_object(),
1229                        CFRange {
1230                            location: 0,
1231                            length: char_len,
1232                        },
1233                        KCFStringEncoding::UTF8.bits,
1234                        0,
1235                        false,
1236                        std::ptr::null_mut(),
1237                        0,
1238                        &mut bytes_required,
1239                    );
1240
1241                    // Then, allocate the buffer and actually copy.
1242                    let mut buffer = vec![b'\x00'; bytes_required as usize];
1243
1244                    let mut bytes_used: CFIndex = 0;
1245                    let chars_written = CFStringGetBytes(
1246                        cf_str.get_internal_object(),
1247                        CFRange {
1248                            location: 0,
1249                            length: char_len,
1250                        },
1251                        KCFStringEncoding::UTF8.bits,
1252                        0,
1253                        false,
1254                        buffer.as_mut_ptr(),
1255                        buffer.len() as CFIndex,
1256                        &mut bytes_used,
1257                    );
1258                    assert_eq!(chars_written, char_len);
1259
1260                    // This is dangerous; we over-allocate and null-terminate the string (during
1261                    // initialization).
1262                    assert_eq!(bytes_used, buffer.len() as CFIndex);
1263                    Cow::Owned(String::from_utf8_unchecked(buffer))
1264                }
1265                _ => {
1266                    let c_str = CStr::from_ptr(c_string);
1267                    String::from_utf8_lossy(c_str.to_bytes())
1268                }
1269            }
1270        }
1271    }
1272}
1273
1274impl<'a> IntoIterator for &'a CFString {
1275    type Item = UniChar;
1276    type IntoIter = Iter<'a>;
1277
1278    fn into_iter(self) -> Self::IntoIter {
1279        self.iter()
1280    }
1281}
1282
1283impl fmt::Display for CFString {
1284    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1285        fmt.write_str(&Cow::from(self))
1286    }
1287}
1288
1289impl fmt::Debug for CFString {
1290    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1291        write!(f, "\"{self}\"")
1292    }
1293}
1294
1295impl PartialEq for CFString {
1296    fn eq(&self, other: &Self) -> bool {
1297        unsafe {
1298            matches!(
1299                CFStringCompare(
1300                    self.get_internal_object(),
1301                    other.get_internal_object(),
1302                    CFStringCompareFlags::DEFAULT,
1303                ),
1304                CFComparisonResult::KCFCompareEqualTo
1305            )
1306        }
1307    }
1308}
1309
1310impl Eq for CFString {}
1311
1312impl PartialEq<&str> for CFString {
1313    fn eq(&self, other: &&str) -> bool {
1314        &self.to_string() == other
1315    }
1316}
1317
1318extern "C" {
1319    pub fn CFStringCreateArrayBySeparatingStrings(
1320        alloc: CFAllocatorRef,
1321        string: CFStringRef,
1322        separator: CFStringRef,
1323    ) -> CFArrayRef;
1324
1325    pub fn CFStringCreateByCombiningStrings(
1326        alloc: CFAllocatorRef,
1327        array: CFArrayRef,
1328        separator: CFStringRef,
1329    ) -> CFStringRef;
1330
1331    pub fn CFStringCreateCopy(alloc: CFAllocatorRef, string: CFStringRef) -> CFStringRef;
1332
1333    pub fn CFStringCreateFromExternalRepresentation(
1334        alloc: CFAllocatorRef,
1335        data: CFDataRef,
1336        encoding: CFStringEncoding,
1337    ) -> CFStringRef;
1338
1339    pub fn CFStringCreateWithBytes(
1340        alloc: CFAllocatorRef,
1341        bytes: *const UInt8,
1342        num_bytes: CFIndex,
1343        encoding: CFStringEncoding,
1344        is_external_representation: Boolean,
1345    ) -> CFStringRef;
1346
1347    pub fn CFStringCreateWithBytesNoCopy(
1348        alloc: CFAllocatorRef,
1349        bytes: *const UInt8,
1350        num_bytes: CFIndex,
1351        encoding: CFStringEncoding,
1352        is_external_representation: Boolean,
1353        contents_deallocator: CFAllocatorRef,
1354    ) -> CFStringRef;
1355
1356    pub fn CFStringCreateWithCharacters(
1357        alloc: CFAllocatorRef,
1358        chars: *const UniChar,
1359        num_chars: CFIndex,
1360    ) -> CFStringRef;
1361
1362    pub fn CFStringCreateWithCharactersNoCopy(
1363        alloc: CFAllocatorRef,
1364        chars: *const UniChar,
1365        num_chars: CFIndex,
1366        contents_deallocator: CFAllocatorRef,
1367    ) -> CFStringRef;
1368
1369    pub fn CFStringCreateWithCString(
1370        alloc: CFAllocatorRef,
1371        c_str: *const c_char,
1372        encoding: CFStringEncoding,
1373    ) -> CFStringRef;
1374
1375    pub fn CFStringCreateWithCStringNoCopy(
1376        alloc: CFAllocatorRef,
1377        c_str: *const c_char,
1378        encoding: CFStringEncoding,
1379        contents_deallocator: CFAllocatorRef,
1380    ) -> CFStringRef;
1381
1382    pub fn CFStringCreateWithFormat(
1383        alloc: CFAllocatorRef,
1384        format_options: CFDictionaryRef,
1385        format: CFStringRef,
1386        ...
1387    ) -> CFStringRef;
1388
1389    pub fn CFStringCreateWithFormatAndArguments(
1390        alloc: CFAllocatorRef,
1391        format_options: CFDictionaryRef,
1392        format: CFStringRef,
1393        va_list: va_list::VaList,
1394    ) -> CFStringRef;
1395
1396    pub fn CFStringCreateWithPascalString(
1397        alloc: CFAllocatorRef,
1398        p_str: ConstStr255Param,
1399        encoding: CFStringEncoding,
1400    ) -> CFStringRef;
1401
1402    pub fn CFStringCreateWithPascalStringNoCopy(
1403        alloc: CFAllocatorRef,
1404        p_str: ConstStr255Param,
1405        encoding: CFStringEncoding,
1406        contents_deallocator: CFAllocatorRef,
1407    ) -> CFStringRef;
1408
1409    pub fn CFStringCreateWithSubstring(
1410        alloc: CFAllocatorRef,
1411        s: CFStringRef,
1412        range: CFRange,
1413    ) -> CFStringRef;
1414
1415    pub fn CFStringCreateArrayWithFindResults(
1416        alloc: CFAllocatorRef,
1417        string: CFStringRef,
1418        string_to_find: CFStringRef,
1419        range_to_search: CFRange,
1420        compare_options: CFStringCompareFlags,
1421    ) -> CFArrayRef;
1422
1423    pub fn CFStringFind(
1424        string: CFStringRef,
1425        string_to_find: CFStringRef,
1426        compare_options: CFStringCompareFlags,
1427    ) -> CFRange;
1428
1429    pub fn CFStringFindCharacterFromSet(
1430        string: CFStringRef,
1431        set: CFCharacterSetRef,
1432        range_to_search: CFRange,
1433        search_options: CFStringCompareFlags,
1434        result: *mut CFRange,
1435    ) -> bool;
1436
1437    pub fn CFStringFindWithOptions(
1438        string: CFStringRef,
1439        string_to_find: CFStringRef,
1440        range_to_search: CFRange,
1441        search_options: CFStringCompareFlags,
1442        result: *mut CFRange,
1443    ) -> bool;
1444
1445    pub fn CFStringFindWithOptionsAndLocale(
1446        string: CFStringRef,
1447        string_to_find: CFStringRef,
1448        range_to_search: CFRange,
1449        search_options: CFStringCompareFlags,
1450        locale: CFLocaleRef,
1451        result: *mut CFRange,
1452    ) -> bool;
1453
1454    pub fn CFStringGetLineBounds(
1455        string: CFStringRef,
1456        range: CFRange,
1457        line_begin_index: *mut CFIndex,
1458        line_end_index: *mut CFIndex,
1459        contents_end_index: *mut CFIndex,
1460    );
1461
1462    pub fn CFStringCompare(
1463        string1: CFStringRef,
1464        string2: CFStringRef,
1465        compare_options: CFStringCompareFlags,
1466    ) -> CFComparisonResult;
1467
1468    pub fn CFStringCompareWithOptions(
1469        string1: CFStringRef,
1470        string2: CFStringRef,
1471        range_to_compare: CFRange,
1472        compare_options: CFStringCompareFlags,
1473    ) -> CFComparisonResult;
1474
1475    pub fn CFStringCompareWithOptionsAndLocale(
1476        string1: CFStringRef,
1477        string2: CFStringRef,
1478        range_to_compare: CFRange,
1479        compare_options: CFStringCompareFlags,
1480        locale: CFLocaleRef,
1481    ) -> CFComparisonResult;
1482
1483    pub fn CFStringHasPrefix(string: CFStringRef, prefix: CFStringRef) -> Boolean;
1484
1485    pub fn CFStringHasSuffix(string: CFStringRef, suffix: CFStringRef) -> Boolean;
1486
1487    pub fn CFStringCreateExternalRepresentation(
1488        alloc: CFStringRef,
1489        string: CFStringEncoding,
1490        encoding: CFStringEncoding,
1491        loss_byte: UInt8,
1492    ) -> CFDataRef;
1493
1494    pub fn CFStringGetBytes(
1495        string: CFStringRef,
1496        range: CFRange,
1497        encoding: CFStringEncoding,
1498        loss_byte: UInt8,
1499        is_external_representation: Boolean,
1500        buffer: *mut UInt8,
1501        max_buf_len: CFIndex,
1502        used_buf_len: *mut CFIndex,
1503    ) -> CFIndex;
1504
1505    pub fn CFStringGetCharacterAtIndex(string: CFStringRef, idx: CFIndex) -> UniChar;
1506
1507    pub fn CFStringGetCharacters(string: CFStringRef, range: CFRange, buffer: &mut [UniChar]);
1508
1509    pub fn CFStringGetCharactersPtr(string: CFStringRef) -> *const UniChar;
1510
1511    pub fn CFStringGetCharacterFromInlineBuffer(
1512        buf: *mut CFStringInlineBuffer,
1513        idx: CFIndex,
1514    ) -> UniChar;
1515
1516    pub fn CFStringGetCString(
1517        string: CFStringRef,
1518        buffer: &mut [c_char],
1519        buffer_size: CFIndex,
1520        encoding: CFStringEncoding,
1521    ) -> Boolean;
1522
1523    pub fn CFStringGetCStringPtr(string: CFStringRef, encoding: CFStringEncoding) -> *const c_char;
1524
1525    pub fn CFStringGetLength(string: CFStringRef) -> CFIndex;
1526
1527    pub fn CFStringGetPascalString(
1528        string: CFStringRef,
1529        buffer: StringPtr,
1530        buffer_size: CFIndex,
1531        encoding: CFStringEncoding,
1532    ) -> Boolean;
1533
1534    pub fn CFStringGetPascalStringPtr(
1535        string: CFStringRef,
1536        encoding: CFStringEncoding,
1537    ) -> ConstStr255Param;
1538
1539    pub fn CFStringGetRangeOfComposedCharactersAtIndex(
1540        string: CFStringRef,
1541        index: CFIndex,
1542    ) -> CFRange;
1543
1544    pub fn CFStringInitInlineBuffer(s: CFStringRef, buf: *mut CFStringInlineBuffer, range: CFRange);
1545
1546    pub fn CFStringGetHyphenationLocationBeforeIndex(
1547        string: CFStringRef,
1548        location: CFIndex,
1549        limit_range: CFRange,
1550        options: CFOptionFlags,
1551        locale: CFLocaleRef,
1552        character: *mut UTF32Char,
1553    ) -> CFIndex;
1554
1555    pub fn CFStringIsHyphenationAvailableForLocale(locale: CFLocaleRef) -> Boolean;
1556
1557    pub fn CFStringConvertEncodingToIANACharSetName(encoding: CFStringEncoding) -> CFStringRef;
1558
1559    pub fn CFStringConvertEncodingToNSStringEncoding(encoding: CFStringEncoding) -> c_ulong;
1560
1561    pub fn CFStringConvertEncodingToWindowsCodepage(encoding: CFStringEncoding) -> UInt32;
1562
1563    pub fn CFStringConvertIANACharSetNameToEncoding(string: CFStringRef) -> CFStringEncoding;
1564
1565    pub fn CFStringConvertNSStringEncodingToEncoding(encoding: c_ulong) -> CFStringEncoding;
1566
1567    pub fn CFStringConvertWindowsCodepageToEncoding(codepage: UInt32) -> CFStringEncoding;
1568
1569    pub fn CFStringGetFastestEncoding(string: CFStringRef) -> CFStringEncoding;
1570
1571    pub fn CFStringGetListOfAvailableEncodings() -> *const CFStringEncoding;
1572
1573    pub fn CFStringGetMaximumSizeForEncoding(
1574        length: CFIndex,
1575        encoding: CFStringEncoding,
1576    ) -> CFIndex;
1577
1578    pub fn CFStringGetMostCompatibleMacStringEncoding(
1579        encoding: CFStringEncoding,
1580    ) -> CFStringEncoding;
1581
1582    pub fn CFStringGetNameOfEncoding(encoding: CFStringEncoding) -> CFStringRef;
1583
1584    pub fn CFStringGetSmallestEncoding(string: CFStringRef) -> CFStringEncoding;
1585
1586    pub fn CFStringGetSystemEncoding() -> CFStringEncoding;
1587
1588    pub fn CFStringIsEncodingAvailable(encoding: CFStringEncoding) -> Boolean;
1589
1590    pub fn CFStringGetDoubleValue(s: CFStringRef) -> c_double;
1591
1592    pub fn CFStringGetIntValue(s: CFStringRef) -> SInt32;
1593
1594    pub fn CFShowStr(s: CFStringRef);
1595
1596    pub fn CFStringGetTypeID() -> CFTypeID;
1597
1598    pub fn CFStringCreateWithFileSystemRepresentation(
1599        alloc: CFAllocatorRef,
1600        buffer: *const c_char,
1601    ) -> CFStringRef;
1602
1603    pub fn CFStringGetFileSystemRepresentation(
1604        string: CFStringRef,
1605        buffer: &mut [c_char],
1606        max_buf_len: CFIndex,
1607    ) -> Boolean;
1608
1609    pub fn CFStringGetMaximumSizeOfFileSystemRepresentation(string: CFStringRef) -> CFIndex;
1610
1611    pub fn CFStringGetParagraphBounds(
1612        string: CFStringRef,
1613        range: CFRange,
1614        par_begin_index: *mut CFIndex,
1615        par_end_index: *mut CFIndex,
1616        contents_end_index: *mut CFIndex,
1617    );
1618
1619    pub fn CFStringGetLongCharacterForSurrogatePair(
1620        surrogate_high: UniChar,
1621        surrogate_low: UniChar,
1622    ) -> UTF32Char;
1623
1624    pub fn CFStringGetSurrogatePairForLongCharacter(
1625        character: UTF32Char,
1626        surrogates: &mut [UniChar],
1627    ) -> Boolean;
1628
1629    pub fn CFStringIsSurrogateHighCharacter(character: UniChar) -> Boolean;
1630
1631    pub fn CFStringIsSurrogateLowCharacter(character: UniChar) -> Boolean;
1632}
1633
1634#[cfg(test)]
1635mod tests {
1636
1637    use crate::core_foundation::{kCFAllocatorDefault, CFRange, CFTypeObject};
1638
1639    use super::{CFString, KCFStringEncoding};
1640
1641    #[test]
1642    fn test_to_string() {
1643        let original = "The quick brown fox jumped over the slow lazy dog.";
1644        let cfstr = CFString::with_str(original);
1645        let converted = cfstr.to_string();
1646        assert_eq!(converted, original);
1647    }
1648
1649    #[test]
1650    fn test_index() {
1651        let s = "Hello World!";
1652        let native_str = CFString::with_str(s);
1653
1654        for i in 0..s.len() {
1655            assert_eq!(
1656                s.chars().nth(i).unwrap(),
1657                native_str.iter().nth(i).unwrap() as u8 as char
1658            );
1659        }
1660    }
1661
1662    #[test]
1663    fn test_cmp_cf_string() {
1664        let native_str1 = CFString::with_str("Hello World!");
1665        let native_str2 = CFString::with_str("Hello World!");
1666        let native_str3 = CFString::with_str("Goodbye World!");
1667
1668        assert_eq!(native_str1, native_str2);
1669        assert_ne!(native_str1, native_str3);
1670    }
1671
1672    #[test]
1673    fn test_cmp_string() {
1674        let s = "Hello World!";
1675        let native_str = CFString::with_str(s);
1676
1677        assert_eq!(native_str, s);
1678    }
1679
1680    #[test]
1681    fn test_create_with_bytes() {
1682        unsafe {
1683            let original = "The quick brown fox jumped over the slow lazy dog.";
1684            let cfstr = CFString::create_with_bytes(
1685                kCFAllocatorDefault,
1686                original.as_ptr(),
1687                original.bytes().len() as u64,
1688                KCFStringEncoding::UTF8.bits,
1689                false,
1690            );
1691
1692            assert_eq!(cfstr, original);
1693        }
1694    }
1695
1696    #[test]
1697    fn test_get_characters() {
1698        let original = "The quick brown fox jumped over the slow lazy dog.";
1699        let cfstr = CFString::with_str(original);
1700
1701        unsafe {
1702            let mut buffer = vec![0; original.len()];
1703
1704            CFString::get_characters(
1705                cfstr.get_internal_object(),
1706                CFRange {
1707                    location: 0,
1708                    length: CFString::get_length(cfstr.get_internal_object()),
1709                },
1710                &mut buffer,
1711            );
1712
1713            assert_eq!(original, String::from_utf16(&buffer).unwrap())
1714        }
1715    }
1716
1717    #[test]
1718    fn test_get_length() {
1719        let original = "The quick brown fox jumped over the slow lazy dog.";
1720        let cfstr = CFString::with_str(original);
1721
1722        unsafe {
1723            assert_eq!(
1724                original.len(),
1725                CFString::get_length(cfstr.get_internal_object()) as usize
1726            )
1727        }
1728    }
1729}