my_ecs/util/
str.rs

1//! String utilities.
2
3/// Determines number of digits at the end of the string.
4///
5/// # Examples
6///
7/// ```
8/// use my_ecs::prelude::*;
9///
10/// assert_eq!(2, str_util::rdigit_num("hello42"));
11/// assert_eq!(0, str_util::rdigit_num("1a")); // Doesn't end with digits.
12/// ```
13pub fn rdigit_num(s: &str) -> usize {
14    let v = s.as_bytes();
15    v.iter().rev().take_while(|c| c.is_ascii_digit()).count()
16}
17
18/// Increases ascii number at the end of the string.
19///
20/// # Examples
21///
22/// ```
23/// use my_ecs::prelude::*;
24///
25/// let mut s = "hello01".to_owned();
26/// str_util::increase_rnumber(&mut s);
27/// assert_eq!("hello02", s.as_str());
28///
29/// let mut s = "hello99".to_owned();
30/// str_util::increase_rnumber(&mut s);
31/// assert_eq!("hello100", s.as_str());
32///
33/// let mut s = "hello".to_owned();
34/// str_util::increase_rnumber(&mut s);
35/// assert_eq!("hello", s.as_str()); // String doesn't end with number.
36/// ```
37pub fn increase_rnumber(s: &mut String) {
38    let n = rdigit_num(s);
39    if n == 0 {
40        return;
41    }
42
43    let mut carry = 1;
44    // Safety: In UTF-8, byte starts with 0 is same with the ascii character.
45    unsafe {
46        let v = s.as_bytes_mut();
47        for c in v.iter_mut().rev().take(n) {
48            if carry == 0 {
49                return;
50            }
51            let d = *c - b'0' + carry;
52            carry = d / 10;
53            *c = d % 10 + b'0';
54        }
55        if carry > 0 {
56            s.insert(s.len() - n, (carry + b'0') as char);
57        }
58    }
59}