1use std::{collections::TryReserveError, ops::RangeBounds};
19pub trait FluentString: Sized {
20 #[must_use]
22 fn f_clear(self) -> Self;
23 #[must_use]
25 fn f_insert(self, idx: usize, ch: char) -> Self;
26 #[must_use]
28 fn f_insert_str(self, idx: usize, string: &str) -> Self;
29 #[must_use]
31 fn f_push(self, ch: char) -> Self;
32 #[must_use]
34 fn f_push_str(self, string: &str) -> Self;
35 #[must_use]
37 fn f_replace_range<R>(self, range: R, replace_with: &str) -> Self
38 where
39 R: RangeBounds<usize>;
40 #[must_use]
42 fn f_reserve(self, additional: usize) -> Self;
43 #[must_use]
45 fn f_reserve_exact(self, additional: usize) -> Self;
46 #[must_use]
48 fn f_retain<F>(self, f: F) -> Self
49 where
50 F: FnMut(char) -> bool;
51 #[must_use]
53 fn f_shrink_to(self, min_capacity: usize) -> Self;
54 #[must_use]
56 fn f_shrink_to_fit(self) -> Self;
57 #[must_use]
59 fn f_truncate(self, new_len: usize) -> Self;
60 fn f_try_reserve(self, additional: usize) -> Result<Self, TryReserveError>;
64 fn f_try_reserve_exact(self, additional: usize) -> Result<Self, TryReserveError>;
68
69 #[must_use]
71 fn f_push_if<F>(self, ch: char, f: F) -> Self
72 where
73 F: Fn(&Self, char) -> bool,
74 {
75 if f(&self, ch) {
76 self.f_push(ch)
77 } else {
78 self
79 }
80 }
81
82 #[must_use]
84 fn f_push_str_if<F>(self, string: &str, f: F) -> Self
85 where
86 F: Fn(&Self, &str) -> bool,
87 {
88 if f(&self, string) {
89 self.f_push_str(string)
90 } else {
91 self
92 }
93 }
94
95 #[must_use]
97 fn f_truncate_if<F>(self, f: F) -> Self
98 where
99 F: Fn(&Self) -> Option<usize>,
100 {
101 match f(&self) {
102 Some(l) => self.f_truncate(l),
103 None => self
104 }
105 }
106}
107
108impl FluentString for String {
111 fn f_clear(mut self) -> Self {
112 self.clear();
113 self
114 }
115
116 fn f_insert(mut self, idx: usize, ch: char) -> Self {
117 self.insert(idx, ch);
118 self
119 }
120
121 fn f_insert_str(mut self, idx: usize, string: &str) -> Self {
122 self.insert_str(idx, string);
123 self
124 }
125
126 fn f_push(mut self, ch: char) -> Self {
127 self.push(ch);
128 self
129 }
130
131 fn f_push_str(mut self, string: &str) -> Self {
132 self.push_str(string);
133 self
134 }
135
136 fn f_replace_range<R>(mut self, range: R, replace_with: &str) -> Self
137 where
138 R: RangeBounds<usize>,
139 {
140 self.replace_range(range, replace_with);
141 self
142 }
143
144 fn f_reserve(mut self, additional: usize) -> Self {
145 self.reserve(additional);
146 self
147 }
148
149 fn f_reserve_exact(mut self, additional: usize) -> Self {
150 self.reserve_exact(additional);
151 self
152 }
153
154 fn f_retain<F>(mut self, f: F) -> Self
155 where
156 F: FnMut(char) -> bool,
157 {
158 self.retain(f);
159 self
160 }
161
162 fn f_shrink_to(mut self, min_capacity: usize) -> Self {
163 self.shrink_to(min_capacity);
164 self
165 }
166
167 fn f_shrink_to_fit(mut self) -> Self {
168 self.shrink_to_fit();
169 self
170 }
171
172 fn f_truncate(mut self, new_len: usize) -> Self {
173 self.truncate(new_len);
174 self
175 }
176
177 fn f_try_reserve(mut self, additional: usize) -> Result<Self, TryReserveError> {
178 self.try_reserve(additional).map(|()| self)
179 }
180
181 fn f_try_reserve_exact(mut self, additional: usize) -> Result<Self, TryReserveError> {
182 self.try_reserve_exact(additional).map(|()| self)
183 }
184}
185
186impl FluentString for &mut String {
189 fn f_clear(self) -> Self {
190 self.clear();
191 self
192 }
193
194 fn f_insert(self, idx: usize, ch: char) -> Self {
195 self.insert(idx, ch);
196 self
197 }
198
199 fn f_insert_str(self, idx: usize, string: &str) -> Self {
200 self.insert_str(idx, string);
201 self
202 }
203
204 fn f_push(self, ch: char) -> Self {
205 self.push(ch);
206 self
207 }
208
209 fn f_push_str(self, string: &str) -> Self {
210 self.push_str(string);
211 self
212 }
213
214 fn f_replace_range<R>(self, range: R, replace_with: &str) -> Self
215 where
216 R: RangeBounds<usize>,
217 {
218 self.replace_range(range, replace_with);
219 self
220 }
221
222 fn f_reserve(self, additional: usize) -> Self {
223 self.reserve(additional);
224 self
225 }
226
227 fn f_reserve_exact(self, additional: usize) -> Self {
228 self.reserve_exact(additional);
229 self
230 }
231
232 fn f_retain<F>(self, f: F) -> Self
233 where
234 F: FnMut(char) -> bool,
235 {
236 self.retain(f);
237 self
238 }
239
240 fn f_shrink_to(self, min_capacity: usize) -> Self {
241 self.shrink_to(min_capacity);
242 self
243 }
244
245 fn f_shrink_to_fit(self) -> Self {
246 self.shrink_to_fit();
247 self
248 }
249
250 fn f_truncate(self, new_len: usize) -> Self {
251 self.truncate(new_len);
252 self
253 }
254
255 fn f_try_reserve(self, additional: usize) -> Result<Self, TryReserveError> {
256 self.try_reserve(additional).map(|()| self)
257 }
258
259 fn f_try_reserve_exact(self, additional: usize) -> Result<Self, TryReserveError> {
260 self.try_reserve_exact(additional).map(|()| self)
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
270 fn test_owned_clear() {
271 assert_eq!("this is a string".to_string().f_clear().len(), 0);
272 }
273 #[test]
274 fn test_owned_insert() {
275 assert!("this is a string"
276 .to_string()
277 .f_insert(5, 'b')
278 .eq_ignore_ascii_case("THIS BIS A STRING"));
279 }
280 #[test]
281 fn test_owned_insert_str() {
282 assert!("this is a string"
283 .to_string()
284 .f_insert_str(8, "not ")
285 .eq_ignore_ascii_case("THIS IS NOT A STRING"));
286 }
287 #[test]
288 fn test_owned_push() {
289 assert!("this is a string"
290 .to_string()
291 .f_push('P')
292 .eq_ignore_ascii_case("THIS IS A STRINGP"));
293 }
294 #[test]
295 fn test_owned_push_str() {
296 assert!("this is a string"
297 .to_string()
298 .f_push_str("PUP")
299 .eq_ignore_ascii_case("THIS IS A STRINGPUP"));
300 }
301 #[test]
302 fn test_owned_replace_range() {
303 assert!("this is a string"
304 .to_string()
305 .f_replace_range(7..9, " not your")
306 .eq_ignore_ascii_case("THIS IS NOT YOUR STRING"));
307 }
308 #[test]
309 fn test_owned_reserve() {
310 assert_eq!(String::with_capacity(10).f_reserve(20).capacity(), 20);
311 }
312 #[test]
313 fn test_owned_reserve_exact() {
314 assert_eq!(String::with_capacity(10).f_reserve_exact(20).capacity(), 20);
315 }
316 #[test]
317 fn test_owned_retain() {
318 assert!("this is a string"
319 .to_string()
320 .f_retain(|c| c != 't')
321 .eq_ignore_ascii_case("HIS IS A SRING"));
322 }
323 #[test]
324 fn test_owned_shrink_to() {
325 assert_eq!(
326 String::with_capacity(30)
327 .f_push_str("this is a string")
328 .f_shrink_to(20)
329 .capacity(),
330 20
331 );
332 }
333 #[test]
334 fn test_owned_shrink_to_fit() {
335 assert_eq!(
336 String::with_capacity(30)
337 .f_push_str("this is a string")
338 .f_shrink_to_fit()
339 .capacity(),
340 16
341 );
342 }
343 #[test]
344 fn test_owned_truncate() {
345 assert!("this is a string"
346 .to_string()
347 .f_truncate(4)
348 .eq_ignore_ascii_case("THIS"));
349 }
350 #[test]
351 fn test_owned_try_reserve() {
352 assert_eq!(
353 String::with_capacity(10)
354 .f_try_reserve(20)
355 .unwrap()
356 .capacity(),
357 20
358 );
359 }
360 #[test]
361 fn test_owned_try_reserve_exact() {
362 assert_eq!(
363 String::with_capacity(10)
364 .f_try_reserve_exact(20)
365 .unwrap()
366 .capacity(),
367 20
368 );
369 }
370
371 #[test]
372 fn test_owned_push_if_false() {
373 assert_eq!(String::new().f_push_if(',', |s, _c| !s.is_empty()), "");
374 }
375
376 #[test]
377 fn test_owned_push_if_true() {
378 assert_eq!(
379 "hey".to_string().f_push_if(',', |s, _c| !s.is_empty()),
380 "hey,"
381 );
382 }
383
384 #[test]
385 fn test_owned_push_str_if_empty_self() {
386 assert_eq!(
387 String::new().f_push_str_if(",more", |s, s1| !(s.is_empty() || s1.is_empty())),
388 ""
389 );
390 }
391
392 #[test]
393 fn test_owned_push_str_if_empty_str() {
394 assert_eq!(
395 "hey"
396 .to_string()
397 .f_push_str_if("", |s, s1| !(s.is_empty() || s1.is_empty())),
398 "hey"
399 );
400 }
401
402 #[test]
403 fn test_owned_push_str_if_true() {
404 assert_eq!(
405 "hey"
406 .to_string()
407 .f_push_str_if(",more", |s, s1| !(s.is_empty() || s1.is_empty())),
408 "hey,more"
409 );
410 }
411
412 #[test]
413 fn test_owned_truncate_if_some() {
414 assert_eq!(
415 "hey you"
416 .to_string()
417 .f_truncate_if(|s| if s.ends_with(" you") {Some(s.len() - 4)} else {None}),
418 "hey"
419 );
420 }
421
422 #[test]
423 fn test_owned_truncate_if_none() {
424 assert_eq!(
425 "hey you"
426 .to_string()
427 .f_truncate_if(|s| if s.ends_with(" ble") {Some(s.len() - 4)} else {None}),
428 "hey you"
429 );
430 }
431
432 #[test]
434 fn test_ref_clear() {
435 let mut s = "this is a string".to_string();
436 let s = &mut s;
437 assert_eq!(s.f_clear().len(), 0);
438 }
439 #[test]
440 fn test_ref_insert() {
441 let mut s = "this is a string".to_string();
442 let s = &mut s;
443 assert!(s.f_insert(5, 'b').eq_ignore_ascii_case("THIS BIS A STRING"));
444 }
445 #[test]
446 fn test_ref_insert_str() {
447 let mut s = "this is a string".to_string();
448 let s = &mut s;
449 assert!(s
450 .f_insert_str(8, "not ")
451 .eq_ignore_ascii_case("THIS IS NOT A STRING"));
452 }
453 #[test]
454 fn test_ref_push() {
455 let mut s = "this is a string".to_string();
456 let s = &mut s;
457 assert!(s.f_push('P').eq_ignore_ascii_case("THIS IS A STRINGP"));
458 }
459 #[test]
460 fn test_ref_push_str() {
461 let mut s = "this is a string".to_string();
462 let s = &mut s;
463 assert!(s
464 .f_push_str("PUP")
465 .eq_ignore_ascii_case("THIS IS A STRINGPUP"));
466 }
467 #[test]
468 fn test_ref_replace_range() {
469 let mut s = "this is a string".to_string();
470 let s = &mut s;
471 assert!(s
472 .f_replace_range(7..9, " not your")
473 .eq_ignore_ascii_case("THIS IS NOT YOUR STRING"));
474 }
475 #[test]
476 fn test_ref_reserve() {
477 let mut s = String::with_capacity(10);
478 let s = &mut s;
479 assert_eq!(s.f_reserve(20).capacity(), 20);
480 }
481 #[test]
482 fn test_ref_reserve_exact() {
483 let mut s = String::with_capacity(10);
484 let s = &mut s;
485 assert_eq!(s.f_reserve_exact(20).capacity(), 20);
486 }
487 #[test]
488 fn test_ref_retain() {
489 let mut s = "this is a string".to_string();
490 let s = &mut s;
491 assert!(s
492 .f_retain(|c| c != 't')
493 .eq_ignore_ascii_case("HIS IS A SRING"));
494 }
495 #[test]
496 fn test_ref_shrink_to() {
497 let mut s = String::with_capacity(30);
498 let s = &mut s;
499 assert_eq!(
500 s.f_push_str("this is a string").f_shrink_to(20).capacity(),
501 20
502 );
503 }
504 #[test]
505 fn test_ref_shrink_to_fit() {
506 let mut s = String::with_capacity(30);
507 let s = &mut s;
508 assert_eq!(
509 s.f_push_str("this is a string")
510 .f_shrink_to_fit()
511 .capacity(),
512 16
513 );
514 }
515 #[test]
516 fn test_ref_truncate() {
517 let mut s = "this is a string".to_string();
518 let s = &mut s;
519 assert!(s.f_truncate(4).eq_ignore_ascii_case("THIS"));
520 }
521 #[test]
522 fn test_ref_try_reserve() {
523 let mut s = String::with_capacity(10);
524 let s = &mut s;
525 assert_eq!(s.f_try_reserve(20).unwrap().capacity(), 20);
526 }
527 #[test]
528 fn test_ref_try_reserve_exact() {
529 let mut s = String::with_capacity(10);
530 let s = &mut s;
531 assert_eq!(s.f_try_reserve_exact(20).unwrap().capacity(), 20);
532 }
533 #[test]
534 fn test_ref_push_if_false() {
535 let mut s = String::new();
536 let s = &mut s;
537 assert_eq!(s.f_push_if(',', |s, _c| !s.is_empty()), "");
538 }
539
540 #[test]
541 fn test_ref_push_if_true() {
542 let mut s = "hey".to_string();
543 let s = &mut s;
544 assert_eq!(s.f_push_if(',', |s, _c| !s.is_empty()), "hey,");
545 }
546
547 #[test]
548 fn test_ref_push_str_if_empty_self() {
549 let mut s = String::new();
550 let s = &mut s;
551 assert_eq!(
552 s.f_push_str_if(",more", |s, s1| !(s.is_empty() || s1.is_empty())),
553 ""
554 );
555 }
556
557 #[test]
558 fn test_ref_push_str_if_empty_str() {
559 let mut s = "hey".to_string();
560 let s = &mut s;
561 assert_eq!(
562 s.f_push_str_if("", |s, s1| !(s.is_empty() || s1.is_empty())),
563 "hey"
564 );
565 }
566
567 #[test]
568 fn test_ref_push_str_if_true() {
569 let mut s = "hey".to_string();
570 let s = &mut s;
571 assert_eq!(
572 s.f_push_str_if(",more", |s, s1| !(s.is_empty() || s1.is_empty())),
573 "hey,more"
574 );
575 }
576
577 #[test]
578 fn test_ref_truncate_if_some() {
579 let mut s = "hey you".to_string();
580 let s = &mut s;
581 assert_eq!(
582 s.f_truncate_if(|s| if s.ends_with(" you") {Some(s.len() - 4)} else {None}),
583 "hey"
584 );
585 }
586
587 #[test]
588 fn test_ref_truncate_if_none() {
589 let mut s = "hey you".to_string();
590 let s = &mut s;
591 assert_eq!(
592 s.f_truncate_if(|s| if s.ends_with(" ble") {Some(s.len() - 4)} else {None}),
593 "hey you"
594 );
595 }
596}