rust_macios/foundation/
ns_mutable_string.rs

1use objc::{msg_send, sel, sel_impl};
2
3use crate::{
4    foundation::INSString,
5    object,
6    objective_c_runtime::{
7        id,
8        macros::interface_impl,
9        traits::{FromId, PNSObject},
10    },
11};
12
13use super::{
14    NSComparisonResult, NSRange, NSString, NSStringCompareOptions, NSStringTransform, UInt,
15};
16
17object! {
18    /// A mutable string.
19    unsafe pub struct NSMutableString;
20}
21
22#[interface_impl(NSString)]
23impl NSMutableString {
24    /* Creating and Initializing a Mutable String
25     */
26
27    /// Returns an empty NSMutableString object with initial storage for a
28    /// given number of characters.
29    ///
30    /// # Arguments
31    ///
32    /// * `capacity` - The number of characters to allocate space for.
33    ///
34    /// # Returns
35    ///
36    /// An empty NSMutableString object with initial storage for a given number of characters.
37    #[method]
38    pub fn string_with_capacity(capacity: UInt) -> NSMutableString {
39        unsafe {
40            NSMutableString::from_id(msg_send![Self::m_class(), stringWithCapacity: capacity])
41        }
42    }
43
44    /// Returns an NSMutableString object initialized with initial storage for
45    /// a given number of characters,
46    ///
47    /// # Arguments
48    ///
49    /// * `capacity` - The number of characters to allocate space for.
50    #[method]
51    pub fn init_with_capacity(mut self, capacity: UInt) -> NSMutableString
52    where
53        Self: Sized,
54    {
55        unsafe { msg_send![self.m_self(), initWithCapacity: capacity] }
56    }
57
58    /* Modifying a String
59     */
60
61    /// Adds a constructed string to the receiver.
62    ///
63    /// # Arguments
64    ///
65    /// * `string` - The string to append to the receiver.
66    #[method]
67    pub fn append_string<S>(&mut self, string: S)
68    where
69        S: INSString,
70    {
71        unsafe { msg_send![self.m_self(), appendString: string] }
72    }
73
74    /// Transliterates the receiver by applying a specified ICU string transform.
75    ///
76    /// # Arguments
77    ///
78    /// * `transform` - The `StringTransform` to apply.
79    /// * `reverse` - If `true`, the transformation is applied in reverse.
80    /// * `range` - The range of characters to apply the transformation to.
81    /// * `out_range` - The range of characters that were transformed.
82    ///
83    /// # Returns
84    ///
85    /// `true` if the transformation was successful, otherwise `false`.
86    #[method]
87    pub fn apply_transform_reverse_range_updated_range(
88        &mut self,
89        transform: NSStringTransform,
90        reverse: bool,
91        range: NSRange,
92        out_range: NSRange,
93    ) -> bool {
94        unsafe {
95            msg_send![
96                self.m_self(),
97                applyTransform: transform
98                reverse: reverse
99                range: range
100                updatedRange: out_range
101            ]
102        }
103    }
104
105    /// Removes from the receiver the characters in a given range.
106    ///
107    /// # Arguments
108    ///
109    /// * `range` - The range of characters to remove.
110    #[method]
111    pub fn delete_characters_in_range(&mut self, range: NSRange) {
112        unsafe { msg_send![self.m_self(), deleteCharactersInRange: range] }
113    }
114
115    /// Inserts into the receiver the characters of a given string at a given
116    /// location.
117    ///
118    /// # Arguments
119    ///
120    /// * `string` - The string to insert into the receiver.
121    /// * `loc` - The location at which to insert `string`.
122    #[method]
123    pub fn insert_string_at_index<S>(&mut self, string: S, loc: UInt)
124    where
125        S: INSString,
126    {
127        unsafe { msg_send![self.m_self(), insertString: string atIndex: loc] }
128    }
129
130    /// Replaces the characters from aRange with those in `string`.
131    ///
132    /// # Arguments
133    ///
134    /// * `range` - The range of characters to replace.
135    /// * `string` - The string to replace with.
136    #[method]
137    pub fn replace_characters_in_range_with_string<S>(&mut self, range: NSRange, string: S)
138    where
139        S: INSString,
140    {
141        unsafe {
142            msg_send![
143                self.m_self(),
144                replaceCharactersInRange: range
145                withString: string
146            ]
147        }
148    }
149
150    /// Replaces all occurrences of a given string in a given range with
151    /// another given string, returning the number of replacements.
152    #[method]
153    pub fn replace_occurrences_of_string_with_string_options_range<S>(
154        &mut self,
155        target: NSString,
156        replacement: S,
157        options: NSStringCompareOptions,
158        search_range: NSRange,
159    ) -> UInt
160    where
161        S: INSString,
162    {
163        unsafe {
164            msg_send![
165                self.m_self(),
166                replaceOccurrencesOfString: target
167                withString: replacement
168                options: options
169                range: search_range
170            ]
171        }
172    }
173
174    /// Replaces the characters of the receiver with those in a given string.
175    ///
176    /// # Arguments
177    ///
178    /// * `string` - The string to replace the characters of the receiver with. string must not be `null`.
179    #[method]
180    pub fn set_string<S>(&mut self, string: S)
181    where
182        S: INSString,
183    {
184        unsafe { msg_send![self.m_self(), setString: string] }
185    }
186}
187
188impl INSString for NSMutableString {}
189
190impl Default for NSMutableString {
191    fn default() -> Self {
192        Self::m_string()
193    }
194}
195
196impl PartialEq for NSMutableString {
197    fn eq(&self, other: &NSMutableString) -> bool {
198        self.m_localized_compare(other.clone()) == NSComparisonResult::OrderedSame
199    }
200}
201
202impl PartialEq<&str> for NSMutableString {
203    fn eq(&self, other: &&str) -> bool {
204        self.m_localized_compare(NSString::from(*other)) == NSComparisonResult::OrderedSame
205    }
206}
207
208impl From<NSString> for NSMutableString {
209    fn from(string: NSString) -> Self {
210        unsafe {
211            let ptr: id = msg_send![NSString::m_class(), alloc];
212            let ptr: id = msg_send![ptr, initWithString: string];
213            NSMutableString::from_id(ptr)
214        }
215    }
216}
217
218#[cfg(test)]
219mod tests {
220
221    use crate::foundation::{string::Encoding, LatinToKatakana, NSStringCompareOptions};
222
223    use super::*;
224
225    #[test]
226    fn test_tm_string_with_capacity() {
227        let string = NSMutableString::string_with_capacity(10);
228        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 0);
229    }
230
231    #[test]
232    fn test_im_append_string() {
233        let mut string = NSMutableString::string_with_capacity(10);
234        string.append_string(NSString::from("Hello"));
235        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
236    }
237
238    #[test]
239    fn test_im_apply_transform_reverse_range_updated_range() {
240        let mut string = NSMutableString::string_with_capacity(10);
241        string.append_string(NSString::from("Hello"));
242        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
243        assert!(string.m_apply_transform_reverse_range_updated_range(
244            unsafe { LatinToKatakana },
245            false,
246            (0..5).into(),
247            (0..5).into()
248        ));
249    }
250
251    #[test]
252    fn test_im_delete_characters_in_range() {
253        let mut string = NSMutableString::string_with_capacity(10);
254        string.append_string(NSString::from("Hello"));
255        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
256        string.m_delete_characters_in_range((0..5).into());
257        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 0);
258    }
259
260    #[test]
261    fn test_im_insert_string_at_index() {
262        let mut string = NSMutableString::string_with_capacity(10);
263        string.append_string(NSString::from("Hello"));
264        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
265        string.m_insert_string_at_index(NSString::from("World"), 0);
266        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 10);
267    }
268
269    #[test]
270    fn test_im_replace_characters_in_range_with_string() {
271        let mut string = NSMutableString::string_with_capacity(10);
272        string.append_string(NSString::from("Hello"));
273        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
274        string.m_replace_characters_in_range_with_string((0..5).into(), NSString::from("World"));
275        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
276    }
277
278    #[test]
279    fn test_im_replace_occurrences_of_string_with_string_options_range() {
280        let mut string = NSMutableString::string_with_capacity(10);
281        string.append_string(NSString::from("Hello"));
282        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
283        assert_eq!(
284            string.m_replace_occurrences_of_string_with_string_options_range(
285                NSString::from("Hello"),
286                NSString::from("World"),
287                NSStringCompareOptions::CaseInsensitive,
288                (0..5).into()
289            ),
290            1
291        );
292    }
293
294    #[test]
295    fn test_im_set_string() {
296        let mut string = NSMutableString::string_with_capacity(10);
297        string.append_string(NSString::from("Hello"));
298        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
299        string.set_string(NSString::from("World"));
300        assert_eq!(string.m_length_of_bytes_using_encoding(Encoding::UTF8), 5);
301    }
302}