rust_macios/foundation/
ns_string.rs

1use std::{
2    ffi::{CStr, CString},
3    fmt,
4    marker::PhantomData,
5    string::String,
6};
7
8use libc::{c_char, c_void};
9use objc::{
10    class, msg_send,
11    runtime::{Class, Object},
12    sel, sel_impl,
13};
14use objc_id::{Id, ShareId};
15
16use crate::{
17    foundation::NSComparisonResult,
18    objective_c_runtime::{
19        self, id,
20        macros::interface_impl,
21        nil,
22        traits::{FromId, PNSObject, ToId},
23    },
24    utils::{to_bool, to_optional},
25};
26
27use super::{
28    string::Encoding, Int, NSArray, NSCharacterSet, NSData, NSError, NSLocale, NSMutableString,
29    NSRange, NSStringCompareOptions, NSStringEncodingConversionOptions, NSStringTransform, UInt,
30    NSURL, UTF8_ENCODING,
31};
32
33/// Type for UTF-16 code units.
34#[allow(non_camel_case_types)]
35pub type unichar = u16;
36
37/// This is a mapping to the Objective-C NSString class.
38#[repr(C)]
39pub struct NSString {
40    /// The raw pointer to the Objective-C object.
41    pub ptr: ShareId<Object>,
42    marker: PhantomData<()>,
43}
44
45impl NSString {
46    /// Returns the UTF8 bytes for this `NSString`.
47    pub fn bytes(&self) -> *const c_char {
48        unsafe {
49            let bytes: *const c_char = msg_send![&*self.ptr, UTF8String];
50            bytes
51        }
52    }
53
54    /// Convert this `NSString` into a `&str`.
55    pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> {
56        let bytes = self.bytes();
57
58        unsafe {
59            let bytes = CStr::from_ptr(bytes);
60            bytes.to_str()
61        }
62    }
63}
64
65#[interface_impl(NSObject)]
66impl NSString {
67    /* Creating and Initializing Strings
68     */
69
70    /// Returns an empty string.
71    #[method]
72    pub fn string() -> Self
73    where
74        Self: Sized + FromId,
75    {
76        unsafe { Self::from_id(msg_send![Self::m_class(), string]) }
77    }
78
79    /// Returns an initialized NSString object that contains no characters.
80    #[method]
81    pub fn init(mut self) -> Self
82    where
83        Self: Sized + FromId,
84    {
85        unsafe { Self::from_id(msg_send![self.m_self(), init]) }
86    }
87
88    /// Returns an initialized NSString object containing a given number of bytes from a given
89    /// buffer of bytes interpreted in a given encoding.
90    ///
91    /// # Arguments
92    ///
93    /// * `bytes` - A buffer of bytes interpreted in the encoding specified by encoding.
94    ///
95    /// * `len` - The number of bytes to use from bytes.
96    ///
97    /// * `encoding` - The character encoding applied to bytes. For possible values, see NSStringEncoding.
98    ///
99    /// # Returns
100    ///
101    /// An initialized NSString object containing length bytes from bytes interpreted using the encoding
102    /// encoding. The returned object may be different from the original receiver.
103    #[method]
104    pub fn init_with_bytes_length_encoding(
105        mut self,
106        bytes: *const c_void,
107        len: UInt,
108        encoding: Encoding,
109    ) -> Self
110    where
111        Self: Sized + FromId,
112    {
113        unsafe {
114            Self::from_id(
115                msg_send![self.m_self(), initWithBytes: bytes length: len encoding: encoding],
116            )
117        }
118    }
119
120    /// Returns an initialized NSString object that contains a given number of bytes from a given buffer of bytes interpreted in a given encoding, and optionally frees the buffer.
121    ///
122    /// # Arguments
123    ///
124    /// * `bytes` - A buffer of bytes interpreted in the encoding specified by encoding.
125    /// * `len` - The number of bytes to use from bytes.
126    /// * `encoding` - The character encoding applied to bytes. For possible values, see NSStringEncoding.
127    /// * `free_buffer` - If YES, bytes is freed after use.
128    ///
129    /// # Returns
130    ///
131    /// An initialized NSString object containing length bytes from bytes interpreted using the encoding encoding. The returned object may be different from the original receiver.
132    #[method]
133    pub fn init_with_bytes_no_copy_length_encoding_free_when_done(
134        mut self,
135        bytes: *mut c_void,
136        len: UInt,
137        encoding: Encoding,
138        free_buffer: bool,
139    ) -> Self
140    where
141        Self: Sized + FromId,
142    {
143        unsafe {
144            Self::from_id(msg_send![
145                self.m_self(),
146                initWithBytesNoCopy: bytes length: len encoding: encoding freeWhenDone: free_buffer
147            ])
148        }
149    }
150
151    /// Returns an initialized NSString object that contains a given number of characters from
152    /// a given C array of UTF-16 code units.
153    ///
154    /// # Arguments
155    ///
156    /// * `characters` - A C array of UTF-16 code units; the value must not be NULL.
157    /// * `length` - A C array of UTF-16 code units; the value must not be NULL.
158    ///
159    /// # Returns
160    ///
161    /// An initialized NSString object containing length characters from characters.
162    #[method]
163    pub fn init_with_characters_length(mut self, characters: *const unichar, len: UInt) -> Self
164    where
165        Self: Sized + FromId,
166    {
167        unsafe {
168            Self::from_id(msg_send![self.m_self(), initWithCharacters: characters length: len])
169        }
170    }
171
172    /// Returns an initialized NSString object that contains a given number of characters
173    /// from a given C array of UTF-16 code units.
174    ///
175    /// # Arguments
176    ///
177    /// * `characters` - A C array of UTF-16 code units; the value must not be NULL.
178    /// * `length` - A C array of UTF-16 code units; the value must not be NULL.
179    /// * `free_buffer` - If YES, characters is freed after use.
180    ///
181    /// # Returns
182    ///
183    /// An initialized NSString object containing length characters from characters.
184    #[method]
185    pub fn init_with_characters_no_copy_length_free_when_done(
186        mut self,
187        characters: unichar,
188        length: UInt,
189        free_buffer: bool,
190    ) -> Self
191    where
192        Self: Sized + FromId,
193    {
194        unsafe {
195            Self::from_id(msg_send![
196                self.m_self(),
197                initWithCharactersNoCopy: characters length: length freeWhenDone: free_buffer
198            ])
199        }
200    }
201
202    /// Returns an NSString object initialized by copying the characters from another given string.
203    ///
204    /// # Arguments
205    ///
206    /// * `s` - The string from which to copy characters. This value must not be nil.
207    ///
208    /// # Returns
209    ///
210    /// An NSString object initialized by copying the characters from s.
211    #[method]
212    pub fn init_with_string<S>(mut self, s: S) -> Self
213    where
214        Self: Sized + FromId,
215        S: INSString,
216    {
217        unsafe { Self::from_id(msg_send![self.m_self(), initWithString: s]) }
218    }
219    /// Returns an NSString object initialized using the characters in a given C array,
220    /// interpreted according to a given encoding.
221    ///
222    /// # Arguments
223    ///
224    /// * `c_str` - A C array of bytes.
225    /// * `encoding` - The encoding to use to interpret c_str. For possible values, see `NSStringEncoding`.
226    ///
227    /// # Returns
228    ///
229    /// An NSString object initialized using the characters in c_str,
230    /// interpreted according to encoding.
231    #[method]
232    pub fn init_with_cstring_encoding(mut self, c_str: *const c_char, encoding: Encoding) -> Self
233    where
234        Self: Sized + FromId,
235    {
236        unsafe {
237            Self::from_id(msg_send![self.m_self(), initWithCString: c_str encoding: encoding])
238        }
239    }
240
241    /// Returns an NSString object initialized using the characters in a given C array,
242    /// interpreted according to a UTF8 string.
243    ///
244    /// # Arguments
245    ///
246    /// * `c_str` - A C array of bytes.
247    ///
248    /// # Returns
249    ///
250    /// An NSString object initialized using the characters in c_str,
251    /// interpreted as a UTF8 string.
252    #[method]
253    pub fn init_with_utf8_string(mut self, c_str: *const c_char) -> Self
254    where
255        Self: Sized + FromId,
256    {
257        unsafe { Self::from_id(msg_send![self.m_self(), initWithUTF8String: c_str]) }
258    }
259
260    /// Returns an NSString object initialized by converting given data into
261    /// UTF-16 code units using a given encoding.
262    ///
263    /// # Arguments
264    ///
265    /// * `data` - The data to convert into UTF-16 code units.
266    /// * `encoding` - The encoding to use to interpret data. For possible values, see `NSStringEncoding`.
267    ///
268    /// # Returns
269    ///
270    /// An NSString object initialized by converting data into UTF-16 code units using encoding.
271    #[method]
272    pub fn init_with_data_encoding(mut self, data: NSData, encoding: Encoding) -> Self
273    where
274        Self: Sized + FromId,
275    {
276        unsafe { Self::from_id(msg_send![self.m_self(), initWithData: data encoding: encoding]) }
277    }
278
279    /// Returns a localized string intended for display in a notification alert.
280    ///
281    /// # Arguments
282    ///
283    /// * `key` - The key to use when looking up the string in the app’s Localizable.strings file.
284    /// * `arguments` - An array of values to substitute for escaped characters in the string.
285    #[method]
286    pub fn localized_user_notification_string_for_key_arguments<T>(
287        key: NSString,
288        arguments: NSArray<T>,
289    ) -> NSString
290    where
291        T: PNSObject,
292    {
293        unsafe {
294            msg_send![Self::m_class(), localizedUserNotificationStringForKey:key arguments:arguments]
295        }
296    }
297
298    /// Returns a string containing a given number of characters taken from a
299    /// given C array of UTF-16 code units.
300    ///
301    /// # Arguments
302    ///
303    /// * `characters` - A C array of UTF-16 code units; the value must not be NULL.
304    /// * `length` - A C array of UTF-16 code units; the value must not be NULL.
305    ///
306    /// # Returns
307    ///
308    /// An NSString object containing length characters from characters.
309    #[method]
310    pub fn string_with_characters_length(characters: *const unichar, length: UInt) -> Self
311    where
312        Self: Sized + FromId,
313    {
314        unsafe {
315            Self::from_id(msg_send![Self::m_class(), stringWithCharacters:characters length:length])
316        }
317    }
318
319    /// Returns a string created by copying the characters from another given string.
320    ///
321    /// # Arguments
322    ///
323    /// * `s` - The string from which to copy characters. This value must not be nil.
324    ///
325    /// # Returns
326    ///
327    /// An NSString object initialized by copying the characters from s.
328    #[method]
329    pub fn string_with_string(s: NSString) -> Self
330    where
331        Self: Sized + 'static + FromId,
332    {
333        unsafe { msg_send![Self::m_class(), stringWithString: s] }
334    }
335
336    /// Returns a string containing the bytes in a given C array, interpreted
337    /// according to a given encoding.
338    ///
339    /// # Arguments
340    ///
341    /// * `c_str` - A C array of bytes.
342    /// * `encoding` - The encoding to use to interpret c_str. For possible values, see `NSStringEncoding`.
343    ///
344    /// # Returns
345    ///
346    /// An NSString object containing the bytes in c_str, interpreted according to encoding.
347    #[method]
348    pub fn string_with_cstring_encoding(c_str: *const c_char, encoding: Encoding) -> Self
349    where
350        Self: Sized + FromId,
351    {
352        unsafe {
353            Self::from_id(msg_send![Self::m_class(), stringWithCString:c_str encoding:encoding])
354        }
355    }
356
357    /// Returns a string created by copying the data from a given C array of
358    /// UTF8-encoded bytes.
359    ///
360    /// # Arguments
361    ///
362    /// * `c_str` - A C array of bytes.
363    ///
364    /// # Returns
365    ///
366    /// An NSString object containing the bytes in c_str, interpreted as a UTF8 string.
367    #[method]
368    pub fn string_with_utf8_string(c_str: *const c_char) -> Self
369    where
370        Self: Sized + FromId,
371    {
372        unsafe { Self::from_id(msg_send![Self::m_class(), stringWithUTF8String: c_str]) }
373    }
374
375    /* Creating and Initializing a String from a File
376     */
377
378    /// Returns a string created by reading data from the file at a given path interpreted using a given encoding.
379    #[method]
380    pub fn string_with_contents_of_file_encoding(
381        path: &NSString,
382        enc: Encoding,
383    ) -> Result<Self, NSError>
384    where
385        Self: Sized + FromId,
386    {
387        let mut error = NSError::m_alloc();
388
389        let result = unsafe {
390            Self::from_id(
391                msg_send![Self::m_class(), stringWithContentsOfFile: path.m_self() encoding: enc error: &mut error],
392            )
393        };
394
395        if error.m_self() != nil {
396            Err(error)
397        } else {
398            Ok(result)
399        }
400    }
401
402    /// Returns an [`NSString`] object initialized by reading data from the file at a given path using a given encoding.
403    #[method]
404    pub fn init_with_contents_of_file_encoding(
405        &mut self,
406        path: &NSString,
407        enc: Encoding,
408    ) -> Result<Self, NSError>
409    where
410        Self: Sized + FromId,
411    {
412        let mut error = NSError::m_alloc();
413
414        let result = unsafe {
415            Self::from_id(
416                msg_send![self.m_self(), initWithContentsOfFile: path.m_self() encoding: enc error: &mut error],
417            )
418        };
419
420        if error.m_self() != nil {
421            Err(error)
422        } else {
423            Ok(result)
424        }
425    }
426
427    /// Returns an [`NSString`] object initialized by reading data from the file at a given path using a given encoding.
428    #[method]
429    pub fn string_with_contents_of_file_used_encoding(
430        path: &NSString,
431        enc: Encoding,
432    ) -> Result<Self, NSError>
433    where
434        Self: Sized + FromId,
435    {
436        let mut error = NSError::m_alloc();
437
438        let result = unsafe {
439            Self::from_id(
440                msg_send![Self::m_class(), stringWithContentsOfFile: path.m_self() usedEncoding: enc error: &mut error],
441            )
442        };
443
444        if error.m_self() != nil {
445            Err(error)
446        } else {
447            Ok(result)
448        }
449    }
450
451    /// Returns a string created by reading data from the file at a given path and returns by reference the encoding used to interpret the file.
452    #[method]
453    pub fn init_with_contents_of_file_used_encoding(
454        &mut self,
455        path: &NSString,
456        enc: Encoding,
457    ) -> Result<Self, NSError>
458    where
459        Self: Sized + FromId,
460    {
461        let mut error = NSError::m_alloc();
462
463        let result = unsafe {
464            Self::from_id(
465                msg_send![self.m_self(), initWithContentsOfFile: path.m_self() usedEncoding: enc error: &mut error],
466            )
467        };
468
469        if error.m_self() != nil {
470            Err(error)
471        } else {
472            Ok(result)
473        }
474    }
475
476    /* Creating and Initializing a String from an URL
477     */
478
479    /// Returns a string created by reading data from a given URL interpreted using a given encoding.
480    #[method]
481    pub fn string_with_contents_of_url_encoding(
482        path: &NSURL,
483        enc: Encoding,
484    ) -> Result<Self, NSError>
485    where
486        Self: Sized + FromId,
487    {
488        let mut error = NSError::m_alloc();
489
490        let result = unsafe {
491            Self::from_id(
492                msg_send![Self::m_class(), stringWithContentsOfURL: path.m_self() encoding: enc error: &mut error],
493            )
494        };
495
496        if error.m_self() != nil {
497            Err(error)
498        } else {
499            Ok(result)
500        }
501    }
502
503    /// Returns an [`NSString`] object initialized by reading data from a given URL interpreted using a given encoding.
504    #[method]
505    pub fn init_with_contents_of_url_encoding(
506        &mut self,
507        path: &NSURL,
508        enc: Encoding,
509    ) -> Result<Self, NSError>
510    where
511        Self: Sized + FromId,
512    {
513        let mut error = NSError::m_alloc();
514
515        let result = unsafe {
516            Self::from_id(
517                msg_send![self.m_self(), initWithContentsOfURL: path.m_self() encoding: enc error: &mut error],
518            )
519        };
520
521        if error.m_self() != nil {
522            Err(error)
523        } else {
524            Ok(result)
525        }
526    }
527
528    /// Returns a string created by reading data from a given URL and returns by reference the encoding used to interpret the data.
529    #[method]
530    pub fn string_with_contents_of_url_used_encoding(
531        path: &NSURL,
532        enc: Encoding,
533    ) -> Result<Self, NSError>
534    where
535        Self: Sized + FromId,
536    {
537        let mut error = NSError::m_alloc();
538
539        let result = unsafe {
540            Self::from_id(
541                msg_send![Self::m_class(), stringWithContentsOfURL: path.m_self() usedEncoding: enc error: &mut error],
542            )
543        };
544
545        if error.m_self() != nil {
546            Err(error)
547        } else {
548            Ok(result)
549        }
550    }
551
552    /// Returns an [`NSString`] object initialized by reading data from a given URL and returns by reference the encoding used to interpret the data.
553    #[method]
554    pub fn init_with_contents_of_url_used_encoding(
555        &mut self,
556        path: &NSURL,
557        enc: Encoding,
558    ) -> Result<Self, NSError>
559    where
560        Self: Sized + FromId,
561    {
562        let mut error = NSError::m_alloc();
563
564        let result = unsafe {
565            Self::from_id(
566                msg_send![self.m_self(), initWithContentsOfURL: path.m_self() usedEncoding: enc error: &mut error],
567            )
568        };
569
570        if error.m_self() != nil {
571            Err(error)
572        } else {
573            Ok(result)
574        }
575    }
576
577    /* Getting a String’s Length
578     */
579
580    /// The number of Unicode characters in this string.
581    #[property]
582    pub fn length(&self) -> UInt {
583        unsafe { msg_send![self.m_self(), length] }
584    }
585
586    /// Returns the number of bytes required to store the receiver in a given encoding.
587    ///
588    /// # Arguments
589    ///
590    /// * `enc` - The encoding for which to determine the receiver's length.
591    ///
592    /// # Returns
593    ///
594    /// The number of bytes required to store the receiver in the encoding enc in a
595    /// non-external representation. The length does not include space for a terminating
596    /// NULL character. Returns 0 if the specified encoding cannot be used to convert
597    /// the receiver or if the amount of memory required for storing the results of the
598    /// encoding conversion would exceed NSIntegerMax.
599    #[method]
600    pub fn length_of_bytes_using_encoding(&self, enc: Encoding) -> UInt {
601        unsafe { msg_send![self.m_self(), lengthOfBytesUsingEncoding: enc] }
602    }
603
604    /// Returns the maximum number of bytes needed to store the receiver in a given encoding.
605    ///
606    /// # Arguments
607    ///
608    /// * `enc` - The encoding for which to determine the receiver's length.
609    ///
610    /// # Returns
611    ///
612    /// The maximum number of bytes needed to store the receiver in encoding in a non-external
613    /// representation. The length does not include space for a terminating NULL character.
614    /// Returns 0 if the amount of memory required for storing the results of the encoding
615    /// conversion would exceed NSIntegerMax.
616    #[method]
617    pub fn maximum_length_of_bytes_using_encoding(&self, enc: Encoding) -> Int {
618        unsafe { msg_send![self.m_self(), maximumLengthOfBytesUsingEncoding: enc] }
619    }
620
621    /* Getting Characters and Bytes
622     */
623
624    /// Returns the character at a given UTF-16 code unit index.
625    ///
626    /// # Arguments
627    ///
628    /// * `index` - The character at the array position given by `index`.
629    ///
630    /// # Returns
631    ///
632    /// The character at the array position given by index.
633    #[method]
634    pub fn character_at_index(&self, index: UInt) -> char {
635        unsafe { msg_send![self.m_self(), characterAtIndex: index] }
636    }
637
638    /// Copies characters from a given range in the receiver into a given buffer.
639    ///
640    /// # Arguments
641    ///
642    /// * `buffer` - Upon return, contains the characters from the receiver. buffer must be large enough to contain the characters in the range aRange (aRange.length*sizeof(unichar)).
643    /// * `range` - The range of characters to copy.
644    #[method]
645    pub fn get_characters_range(&self, buffer: *mut unichar, range: NSRange) {
646        unsafe { msg_send![self.m_self(), getCharacters: buffer range: range] }
647    }
648
649    /// Gets a given range of characters as bytes in a specified encoding.
650    ///
651    /// # Arguments
652    ///
653    /// * `buffer` - Upon return, contains the bytes from the receiver. buffer must be large enough to contain the bytes in the range aRange (aRange.length*sizeof(char)).
654    /// * `maxLength - The maximum number of bytes to get.
655    /// * `usedLength` - Upon return, contains the actual number of bytes retrieved.
656    /// * `encoding` - The encoding to use to interpret the bytes. For possible values, see `NSStringEncoding`.
657    /// * `options` - The options to use for converting the receiver into the specified encoding. For possible values, see `NSStringEncodingConversionOptions`.
658    /// * `range` - The range of characters to get.
659    /// * `remainingRange` - Upon return, contains a range containing the remaining characters.
660    #[method]
661    #[allow(clippy::too_many_arguments)]
662    pub fn get_bytes_max_length_used_length_encoding_options_range_remaining_range(
663        &self,
664        buffer: *mut c_void,
665        max_length: Int,
666        used_length: *mut Int,
667        encoding: Encoding,
668        options: NSStringEncodingConversionOptions,
669        range: NSRange,
670        remaining_range: NSRange,
671    ) -> bool {
672        unsafe {
673            to_bool(
674                msg_send![self.m_self(), getBytes: buffer maxLength: max_length usedLength: used_length encoding: encoding options: options range: range remainingRange: remaining_range],
675            )
676        }
677    }
678
679    /* Getting C Strings
680     */
681
682    /// Returns a representation of the string as a C string using a given encoding.
683    ///
684    /// # Arguments
685    ///
686    /// * `encoding` - The encoding to use to interpret the receiver. For possible values, see `NSStringEncoding`.
687    ///
688    /// # Returns
689    ///
690    /// A pointer to a C string containing the receiver. The pointer is owned by the string, and must not be freed by the caller.
691    #[method]
692    pub fn c_string_using_encoding(&self, encoding: Encoding) -> *const c_char {
693        unsafe { msg_send![self.m_self(), cStringUsingEncoding: encoding] }
694    }
695
696    /// Returns a representation of the string as a C string.
697    ///
698    /// # Arguments
699    ///
700    /// * `buffer` - Upon return, contains the characters from the receiver. buffer must be large enough to contain the characters in the receiver.
701    /// * `maxLength` - The maximum number of bytes to write into buffer.
702    /// * `encoding` - The encoding to use to interpret the receiver. For possible values, see `NSStringEncoding`.
703    ///
704    /// # Returns
705    ///
706    /// `true` if the operation was successful, otherwise `false`. Returns `false` if conversion is not possible due to encoding errors or if buffer is too small.
707    #[method]
708    pub fn get_cstring_max_length_encoding(
709        &self,
710        buffer: *mut c_char,
711        max_length: UInt,
712        encoding: Encoding,
713    ) -> bool {
714        unsafe {
715            to_bool(
716                msg_send![self.m_self(), getCString: buffer maxLength: max_length encoding: encoding],
717            )
718        }
719    }
720
721    /// A null-terminated UTF8 representation of the string.
722    #[property]
723    pub fn utf8_string(&self) -> *const c_char {
724        unsafe { msg_send![self.m_self(), UTF8String] }
725    }
726
727    /* Identifying and Comparing Strings
728     */
729
730    /// Returns the result of invoking compare:options: with NSCaseInsensitiveSearch as the only option.
731    ///
732    /// # Arguments
733    ///
734    /// * `string` - The string to compare.
735    ///
736    /// # Returns
737    ///
738    /// Returns an `ComparisonResult` value that indicates the lexical ordering.
739    /// `OrderedAscending` the receiver precedes `string` in lexical ordering,
740    /// `OrderedSame` the receiver and `string` are equivalent in lexical value,
741    /// and `OrderedDescending` if the receiver follows `string`.
742    #[method]
743    pub fn case_insensitive_compare<S>(&self, string: S) -> NSComparisonResult
744    where
745        S: INSString,
746    {
747        unsafe { msg_send![self.m_self(), caseInsensitiveCompare: string] }
748    }
749
750    /// Compares the string with a given string using a case-insensitive, localized, comparison.
751    ///
752    /// # Arguments
753    ///
754    /// * `string` - The string to compare.
755    ///
756    /// # Returns
757    ///
758    /// Returns an `ComparisonResult` value that indicates the lexical ordering.
759    /// `OrderedAscending` the receiver precedes `string` in lexical ordering,
760    /// `OrderedSame` the receiver and `string` are equivalent in lexical value,
761    /// and `OrderedDescending` if the receiver follows `string`
762    #[method]
763    pub fn localized_case_insensitive_compare<S>(&self, string: S) -> NSComparisonResult
764    where
765        S: INSString,
766    {
767        unsafe { msg_send![self.m_self(), localizedCaseInsensitiveCompare: string] }
768    }
769
770    /// Returns the result of invoking compare:options:range: with no options
771    /// and the receiver’s full extent as the range.
772    ///
773    /// # Arguments
774    ///
775    /// * `string` - The string with which to compare the receiver.
776    ///
777    /// # Safety
778    ///
779    /// This value must not be nil. If this value is nil, the behavior is
780    /// undefined and may change in future versions of macOS.
781    ///
782    /// # Returns
783    ///
784    /// Returns an `ComparisonResult` value that indicates the lexical ordering.
785    /// `OrderedAscending` the receiver precedes `string` in lexical ordering,
786    /// `OrderedSame` the receiver and `string` are equivalent in lexical value,
787    /// and `OrderedDescending` if the receiver follows `string`
788    #[method]
789    pub fn compare<S>(&self, string: S) -> NSComparisonResult
790    where
791        S: INSString,
792    {
793        unsafe { msg_send![self.m_self(), compare: string] }
794    }
795
796    /// Returns the result of invoking compare:options:range: with no options
797    /// and the receiver’s full extent as the range.
798    ///
799    /// # Arguments
800    ///
801    /// * `string` - The string with which to compare the receiver.
802    ///
803    /// Returns an `ComparisonResult` value that indicates the lexical ordering.
804    /// `OrderedAscending` the receiver precedes `string` in lexical ordering,
805    /// `OrderedSame` the receiver and `string` are equivalent in lexical value,
806    /// and `OrderedDescending` if the receiver follows `string`
807    #[method]
808    pub fn localized_compare<S>(&self, string: S) -> NSComparisonResult
809    where
810        S: INSString,
811    {
812        unsafe { msg_send![self.m_self(), localizedCompare: string] }
813    }
814
815    /// Compares the string with the specified string using the given options.
816    ///
817    /// # Arguments
818    ///
819    /// * `string` - The string to compare.
820    /// * `mask` - The mask to use when comparing the receiver and `string`.
821    ///
822    /// # Returns
823    ///
824    /// Returns an `ComparisonResult` value that indicates the lexical ordering.
825    #[method]
826    pub fn compare_options<S>(&self, string: S, mask: NSStringCompareOptions) -> NSComparisonResult
827    where
828        S: INSString,
829    {
830        unsafe { msg_send![self.m_self(), compare: string options: mask] }
831    }
832
833    /// Compares the string with the specified string using the given options.
834    ///
835    /// # Arguments
836    ///
837    /// * `string` - The string to compare.
838    /// * `mask` - The mask to use when comparing the receiver and `string`.
839    /// * `range` - The range of the receiver to compare.
840    #[method]
841    pub fn compare_options_range<S>(
842        &self,
843        string: S,
844        mask: NSStringCompareOptions,
845        range: NSRange,
846    ) -> NSComparisonResult
847    where
848        S: INSString,
849    {
850        unsafe { msg_send![self.m_self(), compare: string options: mask range: range] }
851    }
852
853    /// Compares the string using the specified options and returns the lexical ordering for the range.
854    ///
855    /// # Arguments
856    ///
857    /// * `string` - The string to compare.
858    /// * `mask` - The mask to use when comparing the receiver and `string`.
859    /// * `range` - The range to compare.
860    /// * `locale` - The locale to use when comparing the receiver and `string`.
861    ///
862    /// # Returns
863    ///
864    /// Returns an `ComparisonResult` value that indicates the lexical ordering.
865    #[method]
866    pub fn compare_options_range_locale<S>(
867        &self,
868        string: S,
869        mask: NSStringCompareOptions,
870        range: NSRange,
871        locale: NSLocale,
872    ) -> NSComparisonResult
873    where
874        S: INSString,
875    {
876        unsafe {
877            msg_send![self.m_self(), compare: string options: mask range: range locale: locale]
878        }
879    }
880
881    /// Compares strings as sorted by the Finder.
882    ///
883    /// # Arguments
884    ///
885    /// * `string` - The string to compare with the receiver.
886    ///
887    /// # Returns
888    ///
889    /// The result of the comparison.
890    #[method]
891    pub fn localized_standard_compare<S>(&self, string: S) -> NSComparisonResult
892    where
893        S: INSString,
894    {
895        unsafe { msg_send![self.m_self(), localizedStandardCompare: string] }
896    }
897
898    /// Returns a Boolean value that indicates whether a given string matches the beginning characters of the receiver.
899    ///
900    /// # Arguments
901    ///
902    /// * `prefix` - The prefix to search for.
903    ///
904    /// # Returns
905    ///
906    /// Returns `true` if the string begins with the prefix, otherwise `false`.
907    #[method]
908    pub fn has_prefix<S>(&self, prefix: S) -> bool
909    where
910        S: INSString,
911    {
912        unsafe { to_bool(msg_send![self.m_self(), hasPrefix: prefix]) }
913    }
914
915    /// Returns a Boolean value that indicates whether a given string matches the ending characters of the receiver.
916    ///
917    /// # Arguments
918    ///
919    /// * `suffix` - The suffix to search for.
920    ///
921    /// # Returns
922    ///
923    /// Returns `true` if the string ends with the suffix, otherwise `false`.
924    #[method]
925    pub fn has_suffix<S>(&self, suffix: S) -> bool
926    where
927        S: INSString,
928    {
929        unsafe { to_bool(msg_send![self.m_self(), hasSuffix: suffix]) }
930    }
931
932    /// Returns a Boolean value that indicates whether a given string is equal to the receiver using a literal Unicode-based comparison.
933    ///
934    /// # Arguments
935    ///
936    /// * `string` - The string to compare with the receiver.
937    ///
938    /// # Returns
939    ///
940    /// Returns `true` if the string is equal to the receiver, otherwise `false`.
941    #[method]
942    pub fn is_equal_to_string<S>(&self, string: S) -> bool
943    where
944        S: INSString,
945    {
946        unsafe { to_bool(msg_send![self.m_self(), isEqualToString: string]) }
947    }
948
949    /* Combining Strings
950     */
951
952    /// Returns a new string made by appending a given string to the receiver.
953    ///
954    /// # Arguments
955    ///
956    /// * `string` - The string to append to the receiver. This value must not be nil.
957    #[method]
958    pub fn string_by_appending_string<S>(&self, string: S) -> NSString
959    where
960        S: INSString,
961    {
962        unsafe { msg_send![self.m_self(), stringByAppendingString: string] }
963    }
964
965    /// Returns a new string formed from the receiver by either removing characters from the end, or by appending as many occurrences as necessary of a given pad string.
966    ///
967    /// # Arguments
968    ///
969    /// * `new_length` - The number of characters to be contained in the new string.
970    /// * `pad` - The string to use for padding.
971    /// * `starting_at` - The index in `pad_string` from which to start padding.
972    ///
973    /// # Returns
974    ///
975    /// A new string formed from the receiver by either removing characters from the end, or by appending as many occurrences of `pad_string` as necessary.
976    #[method]
977    pub fn string_by_padding_to_length_with_string_starting_at_index<S>(
978        &self,
979        new_length: UInt,
980        pad_string: S,
981        starting_at: UInt,
982    ) -> NSString
983    where
984        S: INSString,
985    {
986        unsafe {
987            NSString::from_id(
988                msg_send![self.m_self(), stringByPaddingToLength: new_length withString: pad_string startingAtIndex: starting_at],
989            )
990        }
991    }
992
993    /* Changing Case
994     */
995
996    /// A lowercase representation of the string.
997    #[property]
998    pub fn lowercase_string(&self) -> NSString {
999        unsafe { NSString::from_id(msg_send![self.m_self(), lowercaseString]) }
1000    }
1001
1002    /// Returns a version of the string with all letters converted to lowercase,
1003    /// taking into account the current locale.
1004    #[property]
1005    pub fn localized_lowercase_string(&self) -> NSString {
1006        unsafe { NSString::from_id(msg_send![self.m_self(), localizedLowercaseString]) }
1007    }
1008
1009    /// Returns a version of the string with all letters converted to
1010    /// lowercase, taking into account the specified locale.
1011    ///
1012    /// # Arguments
1013    ///
1014    /// * `locale` - The locale to use when converting the letters to lowercase.
1015    ///
1016    /// # Returns
1017    ///
1018    /// A new string with all letters converted to lowercase.
1019    #[method]
1020    pub fn lowercase_string_with_locale(&self, locale: NSLocale) -> NSString {
1021        unsafe { NSString::from_id(msg_send![self.m_self(), lowercaseStringWithLocale: locale]) }
1022    }
1023
1024    /// An uppercase representation of the string.
1025    #[property]
1026    pub fn uppercase_string(&self) -> NSString {
1027        unsafe { NSString::from_id(msg_send![self.m_self(), uppercaseString]) }
1028    }
1029
1030    /// Returns a version of the string with all letters converted to uppercase,
1031    /// taking into account the current locale.
1032    #[property]
1033    pub fn localized_uppercase_string(&self) -> NSString {
1034        unsafe { NSString::from_id(msg_send![self.m_self(), localizedUppercaseString]) }
1035    }
1036
1037    /// Returns a version of the string with all letters converted to uppercase,
1038    /// taking into account the specified locale.
1039    ///
1040    /// # Arguments
1041    ///
1042    /// * `locale` - The locale to use when converting the letters to uppercase.
1043    ///
1044    /// # Returns
1045    ///
1046    /// A new string with all letters converted to uppercase.
1047    #[method]
1048    pub fn uppercase_string_with_locale(&self, locale: NSLocale) -> NSString {
1049        unsafe { NSString::from_id(msg_send![self.m_self(), uppercaseStringWithLocale: locale]) }
1050    }
1051
1052    /// A capitalized representation of the string.
1053    #[property]
1054    pub fn capitalized_string(&self) -> NSString {
1055        unsafe { NSString::from_id(msg_send![self.m_self(), capitalizedString]) }
1056    }
1057
1058    /// Returns a capitalized representation of the receiver using the current
1059    /// locale.
1060    #[property]
1061    pub fn localized_capitalized_string(&self) -> NSString {
1062        unsafe { NSString::from_id(msg_send![self.m_self(), localizedCapitalizedString]) }
1063    }
1064
1065    /// Returns a capitalized representation of the receiver using the
1066    /// specified locale.
1067    #[method]
1068    pub fn capitalized_string_with_locale(&self, locale: NSLocale) -> NSString {
1069        unsafe {
1070            NSString::from_id(msg_send![
1071                self.m_self(),
1072                capitalizedStringWithLocale: locale
1073            ])
1074        }
1075    }
1076
1077    /* Dividing Strings
1078     */
1079
1080    /// Returns an array containing substrings from the receiver that have been divided by a given separator.
1081    #[method]
1082    pub fn components_separated_by_string<S>(&self, separator: S) -> NSArray<NSString>
1083    where
1084        S: INSString,
1085    {
1086        unsafe {
1087            NSArray::from_id(msg_send![
1088                self.m_self(),
1089                componentsSeparatedByString: separator
1090            ])
1091        }
1092    }
1093
1094    /// Returns an array containing substrings from the receiver that have been divided by characters in a given set.
1095    #[method]
1096    pub fn components_separated_by_characters_in_set(
1097        &self,
1098        separator: &NSCharacterSet,
1099    ) -> NSArray<NSString> {
1100        unsafe {
1101            NSArray::from_id(msg_send![
1102                self.m_self(),
1103                componentsSeparatedByCharactersInSet: separator.m_self()
1104            ])
1105        }
1106    }
1107
1108    /// Returns a new string made by removing from both ends of the receiver characters contained in a given character set.
1109    #[method]
1110    pub fn string_by_trimming_characters_in_set(&self, set: &NSCharacterSet) -> NSString {
1111        unsafe {
1112            NSString::from_id(msg_send![
1113                self.m_self(),
1114                stringByTrimmingCharactersInSet: set.m_self()
1115            ])
1116        }
1117    }
1118
1119    /// Returns a new string containing the characters of the receiver from the one at a given index to the end.
1120    #[method]
1121    pub fn substring_from_index(&self, from: UInt) -> NSString {
1122        unsafe { NSString::from_id(msg_send![self.m_self(), substringFromIndex: from]) }
1123    }
1124
1125    /// Returns a string object containing the characters of the receiver that lie within a given range.
1126    #[method]
1127    pub fn substring_with_range(&self, range: NSRange) -> NSString {
1128        unsafe { NSString::from_id(msg_send![self.m_self(), substringWithRange: range]) }
1129    }
1130
1131    /// Returns a new string containing the characters of the receiver up to, but not including, the one at a given index.
1132    #[method]
1133    pub fn substring_to_index(&self, to: UInt) -> NSString {
1134        unsafe { NSString::from_id(msg_send![self.m_self(), substringToIndex: to]) }
1135    }
1136
1137    /* Normalizing Strings
1138     */
1139
1140    /// A string made by normalizing the string’s contents using the Unicode Normalization Form D.
1141    #[property]
1142    pub fn decomposed_string_with_canonical_mapping(&self) -> NSString {
1143        unsafe {
1144            NSString::from_id(msg_send![
1145                self.m_self(),
1146                decomposedStringWithCanonicalMapping
1147            ])
1148        }
1149    }
1150
1151    /// A string made by normalizing the receiver’s contents using the Unicode Normalization Form KD.
1152    #[property]
1153    pub fn decomposed_string_with_compatibility_mapping(&self) -> NSString {
1154        unsafe {
1155            NSString::from_id(msg_send![
1156                self.m_self(),
1157                decomposedStringWithCompatibilityMapping
1158            ])
1159        }
1160    }
1161
1162    /// A string made by normalizing the string’s contents using the Unicode Normalization Form C.
1163    #[property]
1164    pub fn precomposed_string_with_canonical_mapping(&self) -> NSString {
1165        unsafe {
1166            NSString::from_id(msg_send![
1167                self.m_self(),
1168                precomposedStringWithCanonicalMapping
1169            ])
1170        }
1171    }
1172
1173    /// A string made by normalizing the receiver’s contents using the Unicode Normalization Form KC.
1174    #[property]
1175    pub fn precomposed_string_with_compatibility_mapping(&self) -> NSString {
1176        unsafe {
1177            NSString::from_id(msg_send![
1178                self.m_self(),
1179                precomposedStringWithCompatibilityMapping
1180            ])
1181        }
1182    }
1183
1184    /* Folding Strings
1185     */
1186
1187    /// Creates a string suitable for comparison by removing the specified character distinctions from a string.
1188    #[method]
1189    pub fn string_by_folding_with_options_locale(
1190        &mut self,
1191        options: NSStringCompareOptions,
1192        locale: &NSLocale,
1193    ) -> NSString {
1194        unsafe {
1195            NSString::from_id(
1196                msg_send![self.m_self(), stringByFoldingWithOptions: options locale: locale.m_self() ],
1197            )
1198        }
1199    }
1200
1201    /* Transforming Strings
1202     */
1203
1204    /// Returns a new string made by appending to the receiver a given string.
1205    ///
1206    /// # Arguments
1207    ///
1208    /// * `transform` - The `StringTransform` to apply.
1209    /// * `reverse` - If `true`, the transformation is applied in reverse.
1210    #[method]
1211    pub fn string_by_applying_transform_reverse(
1212        &mut self,
1213        transform: NSStringTransform,
1214        reverse: bool,
1215    ) -> Option<NSString> {
1216        unsafe {
1217            to_optional(
1218                msg_send![self.m_self(), stringByApplyingTransform: transform reverse: reverse],
1219            )
1220        }
1221    }
1222
1223    /* Finding Characters and Substrings
1224     */
1225
1226    /// Returns a boolean value indicating whether the string contains a given string by performing a case-sensitive, locale-unaware search.
1227    ///
1228    /// # Arguments
1229    ///
1230    /// * `string` - The string to search for.
1231    ///
1232    /// # Returns
1233    ///
1234    /// Returns `true` if `string` is contained in the receiver, otherwise `false`.
1235    #[method]
1236    pub fn contains_string<S>(&self, other: S) -> bool
1237    where
1238        S: INSString,
1239    {
1240        unsafe { to_bool(msg_send![self.m_self(), containsString: other]) }
1241    }
1242
1243    /* Working with Encodings
1244     */
1245
1246    /// Returns a zero-terminated list of the encodings string objects support in the application’s environment.
1247    #[property]
1248    pub fn available_string_encodings() -> *const Encoding {
1249        unsafe { msg_send![Self::m_class(), availableStringEncodings] }
1250    }
1251
1252    /// Returns the C-string encoding assumed for any method accepting a C string as an argument.
1253    #[property]
1254    pub fn default_cstring_encoding() -> Encoding {
1255        unsafe { msg_send![Self::m_class(), defaultCStringEncoding] }
1256    }
1257
1258    /// Returns a Boolean value that indicates whether the receiver can be converted to a given encoding without loss of information.
1259    #[method]
1260    pub fn can_be_converted_to_encoding(&self, encoding: Encoding) -> bool {
1261        unsafe { to_bool(msg_send![self.m_self(), canBeConvertedToEncoding: encoding]) }
1262    }
1263
1264    /// Returns an NSData object containing a representation of the receiver encoded using a given encoding.
1265    #[method]
1266    pub fn data_using_encoding(&self, encoding: Encoding) -> NSData {
1267        unsafe { NSData::from_id(msg_send![self.m_self(), dataUsingEncoding: encoding]) }
1268    }
1269}
1270
1271impl PNSObject for NSString {
1272    fn m_class<'a>() -> &'a Class {
1273        class!(NSString)
1274    }
1275
1276    fn m_self(&self) -> id {
1277        unsafe { msg_send![&*self.ptr, self] }
1278    }
1279}
1280
1281unsafe impl objective_c_runtime::Encode for NSString {
1282    fn encode() -> objc::Encoding {
1283        unsafe { objective_c_runtime::Encoding::from_str("@") }
1284    }
1285}
1286
1287impl Default for NSString {
1288    fn default() -> Self {
1289        Self::string()
1290    }
1291}
1292
1293impl fmt::Debug for NSString {
1294    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1295        write!(f, "{}", self.p_description().as_str().unwrap())
1296    }
1297}
1298
1299impl fmt::Display for NSString {
1300    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
1301        write!(f, "{}", self.p_description().as_str().unwrap())
1302    }
1303}
1304
1305impl Clone for NSString {
1306    fn clone(&self) -> Self {
1307        unsafe { msg_send![&*self.ptr, retain] }
1308    }
1309}
1310
1311impl ToId for NSString {
1312    fn to_id(self) -> id {
1313        unsafe { &mut *self.m_self() }
1314    }
1315}
1316
1317impl FromId for NSString {
1318    unsafe fn from_id(id: id) -> Self {
1319        NSString {
1320            ptr: Id::from_ptr(id),
1321            marker: PhantomData,
1322        }
1323    }
1324}
1325
1326impl From<NSMutableString> for NSString {
1327    fn from(string: NSMutableString) -> Self {
1328        unsafe {
1329            let ptr: id = msg_send![NSString::m_class(), alloc];
1330            let ptr = msg_send![ptr, initWithString: string];
1331            NSString::from_id(ptr)
1332        }
1333    }
1334}
1335
1336impl From<String> for NSString {
1337    /// Creates a new `NSString` from a `String`.
1338    fn from(s: String) -> Self {
1339        let c_string = CString::new(s.clone()).unwrap();
1340        NSString {
1341            ptr: unsafe {
1342                let nsstring: id = msg_send![class!(NSString), alloc];
1343                Id::from_ptr(
1344                    msg_send![nsstring, initWithBytes:c_string.into_raw() as *mut Object
1345                        length:s.len()
1346                        encoding:UTF8_ENCODING
1347                    ],
1348                )
1349            },
1350
1351            marker: PhantomData,
1352        }
1353    }
1354}
1355
1356impl From<&str> for NSString {
1357    /// Creates a new `NSString` from a `&str`.
1358    fn from(s: &str) -> Self {
1359        let objc = unsafe {
1360            let nsstring: *mut Object = msg_send![class!(NSString), alloc];
1361            Id::from_ptr(
1362                msg_send![nsstring, initWithBytes: CString::new(s).unwrap().into_raw() as *mut Object
1363                    length:s.len()
1364                    encoding:UTF8_ENCODING
1365                ],
1366            )
1367        };
1368
1369        NSString {
1370            ptr: objc,
1371            marker: PhantomData,
1372        }
1373    }
1374}
1375
1376impl From<&&str> for NSString {
1377    /// Creates a new `NSString` from a `&str`.
1378    fn from(s: &&str) -> Self {
1379        let objc = unsafe {
1380            let nsstring: *mut Object = msg_send![class!(NSString), alloc];
1381            Id::from_ptr(
1382                msg_send![nsstring, initWithBytes: CString::new(*s).unwrap().into_raw() as *mut Object
1383                    length:s.len()
1384                    encoding:UTF8_ENCODING
1385                ],
1386            )
1387        };
1388
1389        NSString {
1390            ptr: objc,
1391            marker: PhantomData,
1392        }
1393    }
1394}
1395
1396impl From<char> for NSString {
1397    /// Creates a new `NSString` from a `char`.
1398    fn from(c: char) -> Self {
1399        let objc = unsafe {
1400            let nsstring: *mut Object = msg_send![class!(NSString), alloc];
1401            Id::from_ptr(
1402                msg_send![nsstring, initWithBytes: c.encode_utf8(&mut [0; 4]).as_ptr()
1403                    length:1
1404                    encoding:UTF8_ENCODING
1405                ],
1406            )
1407        };
1408
1409        NSString {
1410            ptr: objc,
1411            marker: PhantomData,
1412        }
1413    }
1414}
1415
1416impl From<NSString> for &str {
1417    /// Converts a `NSString` to a `&str`.
1418    fn from(string: NSString) -> Self {
1419        unsafe {
1420            let ptr: *const c_char = msg_send![string.ptr, UTF8String];
1421            CStr::from_ptr(ptr).to_str().unwrap()
1422        }
1423    }
1424}
1425
1426impl From<(&str, Encoding)> for NSString {
1427    /// Creates a new `NSString` from a `&str` and an encoding.
1428    fn from((s, encoding): (&str, Encoding)) -> Self {
1429        let objc = unsafe {
1430            let nsstring: *mut Object = msg_send![class!(NSString), alloc];
1431            Id::from_ptr(msg_send![nsstring, initWithBytes:s.as_ptr()
1432                length:s.len()
1433                encoding:encoding
1434            ])
1435        };
1436
1437        NSString {
1438            ptr: objc,
1439            marker: PhantomData,
1440        }
1441    }
1442}
1443
1444impl PartialEq for NSString {
1445    /// Checks if two `NSString`s are equal.
1446    fn eq(&self, other: &Self) -> bool {
1447        self.localized_compare(other.clone()) == NSComparisonResult::OrderedSame
1448    }
1449}
1450
1451impl Eq for NSString {}
1452
1453impl PartialEq<&str> for NSString {
1454    /// Checks if a `NSString` is equal to a `&str`.
1455    fn eq(&self, other: &&str) -> bool {
1456        self.as_str().unwrap() == *other
1457    }
1458}
1459
1460#[cfg(test)]
1461mod tests {
1462    use crate::foundation::{
1463        string::Encoding, string_transform::LatinToKatakana, NSComparisonResult,
1464    };
1465
1466    use super::*;
1467
1468    #[test]
1469    fn test_from_str() {
1470        let s = NSString::from("Hello, World!");
1471        assert_eq!(s, "Hello, World!");
1472    }
1473
1474    #[test]
1475    fn test_bytes() {
1476        let s = NSString::from("Hello, World!");
1477        let other = s.bytes();
1478        assert_eq!(s.bytes(), other);
1479    }
1480
1481    #[test]
1482    fn test_bytes_len() {
1483        let s = NSString::from("Hello, World!");
1484        assert_eq!(s.length_of_bytes_using_encoding(Encoding::UTF8), 13);
1485    }
1486
1487    #[test]
1488    fn test_as_str() {
1489        let s = NSString::from("Hello, World!");
1490        assert_eq!(s, "Hello, World!");
1491    }
1492
1493    #[test]
1494    fn test_to_string() {
1495        let s = NSString::from("Hello, World!");
1496        assert_eq!(s.to_string(), "Hello, World!".to_string());
1497    }
1498
1499    #[test]
1500    fn test_length() {
1501        let s = NSString::from("Hello, World!");
1502        assert_eq!(s.length(), 13);
1503    }
1504
1505    #[test]
1506    fn test_contains() {
1507        let s = NSString::from("Hello, World!");
1508        assert!(s.contains_string(NSString::from("Hello")));
1509        assert!(!s.contains_string(NSString::from("Goodbye")));
1510    }
1511
1512    #[test]
1513    fn test_character_at() {
1514        let s = NSString::from("Hello, World!");
1515        assert_eq!(s.character_at_index(0), 'H');
1516        assert_eq!(s.character_at_index(1), 'e');
1517        assert_eq!(s.character_at_index(2), 'l');
1518        assert_eq!(s.character_at_index(3), 'l');
1519        assert_eq!(s.character_at_index(4), 'o');
1520        assert_eq!(s.character_at_index(5), ',');
1521        assert_eq!(s.character_at_index(6), ' ');
1522        assert_eq!(s.character_at_index(7), 'W');
1523        assert_eq!(s.character_at_index(8), 'o');
1524        assert_eq!(s.character_at_index(9), 'r');
1525        assert_eq!(s.character_at_index(10), 'l');
1526        assert_eq!(s.character_at_index(11), 'd');
1527        assert_eq!(s.character_at_index(12), '!');
1528    }
1529
1530    #[test]
1531    fn test_has_prefix() {
1532        let s = NSString::from("Hello, World!");
1533        assert!(s.has_prefix(NSString::from("Hello")));
1534        assert!(!s.has_prefix(NSString::from("Goodbye")));
1535    }
1536
1537    #[test]
1538    fn test_has_suffix() {
1539        let s = NSString::from("Hello, World!");
1540        assert!(s.has_suffix(NSString::from("World!")));
1541        assert!(!s.has_suffix(NSString::from("Goodbye")));
1542    }
1543
1544    #[test]
1545    fn test_is_equal_to() {
1546        let s = NSString::from("Hello, World!");
1547        assert!(s.is_equal_to_string(NSString::from("Hello, World!")));
1548        assert!(!s.is_equal_to_string(NSString::from("Goodbye, World!")));
1549    }
1550
1551    #[test]
1552    fn test_length_of_bytes() {
1553        let s = NSString::from("Hello, World!");
1554        assert_eq!(s.length_of_bytes_using_encoding(Encoding::UTF8), 13);
1555    }
1556
1557    #[test]
1558    fn test_maximum_length_of_bytes() {
1559        let s = NSString::from("Hello, World!");
1560        assert_eq!(s.maximum_length_of_bytes_using_encoding(Encoding::UTF8), 39);
1561    }
1562
1563    #[test]
1564    fn test_case_insensitive_compare() {
1565        let s = NSString::from("Hello, World!");
1566        assert_eq!(
1567            s.case_insensitive_compare(NSString::from("hello, world!")),
1568            NSComparisonResult::OrderedSame
1569        );
1570        assert_eq!(
1571            s.case_insensitive_compare(NSString::from("goodbye, world!")),
1572            NSComparisonResult::OrderedDescending
1573        );
1574    }
1575
1576    #[test]
1577    fn test_compare() {
1578        let s = NSString::from("Hello, World!");
1579        assert_eq!(
1580            s.compare(NSString::from("Hello, World!")),
1581            NSComparisonResult::OrderedSame
1582        );
1583        assert_eq!(
1584            s.compare(NSString::from("Goodbye, World!")),
1585            NSComparisonResult::OrderedDescending
1586        );
1587    }
1588
1589    #[test]
1590    fn test_localized_standard_compare() {
1591        let s = NSString::from("Hello, World!");
1592        assert_eq!(
1593            s.localized_standard_compare(NSString::from("Hello, World!")),
1594            NSComparisonResult::OrderedSame
1595        );
1596        assert_eq!(
1597            s.localized_standard_compare(NSString::from("Goodbye, World!")),
1598            NSComparisonResult::OrderedDescending
1599        );
1600    }
1601
1602    #[test]
1603    fn test_applying_transform() {
1604        let mut s = NSString::from("Katakana!");
1605        let transform = unsafe { LatinToKatakana };
1606        assert_eq!(
1607            s.string_by_applying_transform_reverse(transform, false)
1608                .unwrap(),
1609            "カタカナ!"
1610        );
1611    }
1612
1613    #[test]
1614    fn test_im_case_insensitive_compare() {
1615        let s = NSString::from("Hello, World!");
1616        assert_eq!(
1617            s.case_insensitive_compare(NSString::from("hello, world!")),
1618            NSComparisonResult::OrderedSame
1619        );
1620        assert_eq!(
1621            s.case_insensitive_compare(NSString::from("goodbye, world!")),
1622            NSComparisonResult::OrderedDescending
1623        );
1624    }
1625
1626    #[test]
1627    fn test_string_by_padding_to_length_with_string_starting_at_index() {
1628        let s = NSString::from("Hello, World!");
1629
1630        assert_eq!(
1631            s.string_by_padding_to_length_with_string_starting_at_index(20, NSString::from("."), 0),
1632            "Hello, World!......."
1633        );
1634    }
1635}