rocketmq_common/utils/
string_utils.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17use std::collections::BTreeMap;
18use std::collections::HashMap;
19
20use cheetah_string::CheetahString;
21
22pub struct StringUtils;
23
24impl StringUtils {
25    #[inline]
26    pub fn is_not_empty_str(s: Option<&str>) -> bool {
27        s.is_some_and(|s| !s.is_empty())
28    }
29
30    #[inline]
31    pub fn is_not_empty_string(s: Option<&String>) -> bool {
32        s.is_some_and(|s| !s.is_empty())
33    }
34
35    #[inline]
36    pub fn is_not_empty_ch_string(s: Option<&CheetahString>) -> bool {
37        s.is_some_and(|s| !s.is_empty())
38    }
39
40    pub fn parse_delay_level(level_string: &str) -> Result<(BTreeMap<i32, i64>, i32), String> {
41        let time_unit_table = HashMap::from([
42            ('s', 1000),
43            ('m', 1000 * 60),
44            ('h', 1000 * 60 * 60),
45            ('d', 1000 * 60 * 60 * 24),
46        ]);
47
48        let mut delay_level_table = BTreeMap::new();
49
50        let level_array: Vec<&str> = level_string.split(' ').collect();
51        let mut max_delay_level = 0;
52
53        for (i, value) in level_array.iter().enumerate() {
54            // let ch = value.chars().last().unwrap().to_string();
55            let ch = match value.chars().last() {
56                None => {
57                    return Err("Empty time unit".to_string());
58                }
59                Some(value) => value,
60            };
61            let tu = *time_unit_table
62                .get(&ch)
63                .ok_or(format!("Unknown time unit: {ch}"))?;
64
65            let level = i as i32 + 1;
66            if level > max_delay_level {
67                max_delay_level = level;
68            }
69
70            let num_str = &value[0..value.len() - 1];
71            let num = num_str.parse::<i64>().map_err(|e| e.to_string())?;
72            let delay_time_millis = tu * num;
73            delay_level_table.insert(level, delay_time_millis);
74        }
75
76        Ok((delay_level_table, max_delay_level))
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::StringUtils;
83
84    #[test]
85    fn is_not_empty_str_with_some_non_empty_str() {
86        assert!(StringUtils::is_not_empty_str(Some("hello")));
87    }
88
89    #[test]
90    fn is_not_empty_str_with_some_empty_str() {
91        assert!(!StringUtils::is_not_empty_str(Some("")));
92    }
93
94    #[test]
95    fn is_not_empty_str_with_none() {
96        assert!(!StringUtils::is_not_empty_str(None));
97    }
98
99    #[test]
100    fn is_not_empty_string_with_some_non_empty_string() {
101        assert!(StringUtils::is_not_empty_string(Some(&"hello".to_string())));
102    }
103
104    #[test]
105    fn is_not_empty_string_with_some_empty_string() {
106        assert!(!StringUtils::is_not_empty_string(Some(&"".to_string())));
107    }
108
109    #[test]
110    fn is_not_empty_string_with_none() {
111        assert!(!StringUtils::is_not_empty_string(None));
112    }
113
114    #[test]
115    fn parse_delay_level_with_valid_input() {
116        let result = StringUtils::parse_delay_level("1s 2m 3h 4d").unwrap();
117        let (delay_level_table, max_delay_level) = result;
118        assert_eq!(delay_level_table[&1], 1000);
119        assert_eq!(delay_level_table[&2], 2 * 60 * 1000);
120        assert_eq!(delay_level_table[&3], 3 * 60 * 60 * 1000);
121        assert_eq!(delay_level_table[&4], 4 * 24 * 60 * 60 * 1000);
122        assert_eq!(max_delay_level, 4);
123    }
124
125    #[test]
126    fn parse_delay_level_with_unknown_time_unit() {
127        let result = StringUtils::parse_delay_level("1x");
128        assert!(result.is_err());
129        assert_eq!(result.err().unwrap(), "Unknown time unit: x");
130    }
131
132    #[test]
133    fn parse_delay_level_with_invalid_number() {
134        let result = StringUtils::parse_delay_level("1s 2m 3h 4d 5z");
135        assert!(result.is_err());
136        assert_eq!(result.err().unwrap(), "Unknown time unit: z");
137    }
138
139    #[test]
140    fn parse_delay_level_with_empty_string() {
141        let result = StringUtils::parse_delay_level("");
142        assert!(result.is_err());
143    }
144}