rocketmq_model/utils/
string_utils.rs1use std::collections::BTreeMap;
16use std::collections::HashMap;
17
18use cheetah_string::CheetahString;
19
20pub struct StringUtils;
21
22impl StringUtils {
23 #[inline]
24 pub fn is_not_empty_str(s: Option<&str>) -> bool {
25 s.is_some_and(|s| !s.is_empty())
26 }
27
28 #[inline]
29 pub fn is_not_empty_string(s: Option<&String>) -> bool {
30 s.is_some_and(|s| !s.is_empty())
31 }
32
33 #[inline]
34 pub fn is_not_empty_ch_string(s: Option<&CheetahString>) -> bool {
35 s.is_some_and(|s| !s.is_empty())
36 }
37
38 pub fn parse_delay_level(level_string: &str) -> Result<(BTreeMap<i32, i64>, i32), String> {
39 let time_unit_table = HashMap::from([
40 ('s', 1000),
41 ('m', 1000 * 60),
42 ('h', 1000 * 60 * 60),
43 ('d', 1000 * 60 * 60 * 24),
44 ]);
45
46 let mut delay_level_table = BTreeMap::new();
47
48 let level_array: Vec<&str> = level_string.split(' ').collect();
49 let mut max_delay_level = 0;
50
51 for (i, value) in level_array.iter().enumerate() {
52 let ch = match value.chars().last() {
54 None => {
55 return Err("Empty time unit".to_string());
56 }
57 Some(value) => value,
58 };
59 let tu: i64 = *time_unit_table.get(&ch).ok_or(format!("Unknown time unit: {ch}"))?;
60
61 let level = i as i32 + 1;
62 if level > max_delay_level {
63 max_delay_level = level;
64 }
65
66 let num_str = &value[0..value.len() - 1];
67 let num = num_str.parse::<i64>().map_err(|e| e.to_string())?;
68 let delay_time_millis = tu
69 .checked_mul(num)
70 .ok_or_else(|| format!("Delay level milliseconds overflow: {num}{ch}"))?;
71 delay_level_table.insert(level, delay_time_millis);
72 }
73
74 Ok((delay_level_table, max_delay_level))
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::StringUtils;
81
82 #[test]
83 fn is_not_empty_str_with_some_non_empty_str() {
84 assert!(StringUtils::is_not_empty_str(Some("hello")));
85 }
86
87 #[test]
88 fn is_not_empty_str_with_some_empty_str() {
89 assert!(!StringUtils::is_not_empty_str(Some("")));
90 }
91
92 #[test]
93 fn is_not_empty_str_with_none() {
94 assert!(!StringUtils::is_not_empty_str(None));
95 }
96
97 #[test]
98 fn is_not_empty_string_with_some_non_empty_string() {
99 assert!(StringUtils::is_not_empty_string(Some(&"hello".to_string())));
100 }
101
102 #[test]
103 fn is_not_empty_string_with_some_empty_string() {
104 assert!(!StringUtils::is_not_empty_string(Some(&"".to_string())));
105 }
106
107 #[test]
108 fn is_not_empty_string_with_none() {
109 assert!(!StringUtils::is_not_empty_string(None));
110 }
111
112 #[test]
113 fn parse_delay_level_with_valid_input() {
114 let result = StringUtils::parse_delay_level("1s 2m 3h 4d").unwrap();
115 let (delay_level_table, max_delay_level) = result;
116 assert_eq!(delay_level_table[&1], 1000);
117 assert_eq!(delay_level_table[&2], 2 * 60 * 1000);
118 assert_eq!(delay_level_table[&3], 3 * 60 * 60 * 1000);
119 assert_eq!(delay_level_table[&4], 4 * 24 * 60 * 60 * 1000);
120 assert_eq!(max_delay_level, 4);
121 }
122
123 #[test]
124 fn parse_delay_level_with_unknown_time_unit() {
125 let result = StringUtils::parse_delay_level("1x");
126 assert!(result.is_err());
127 assert_eq!(result.err().unwrap(), "Unknown time unit: x");
128 }
129
130 #[test]
131 fn parse_delay_level_with_invalid_number() {
132 let result = StringUtils::parse_delay_level("1s 2m 3h 4d 5z");
133 assert!(result.is_err());
134 assert_eq!(result.err().unwrap(), "Unknown time unit: z");
135 }
136
137 #[test]
138 fn parse_delay_level_with_empty_string() {
139 let result = StringUtils::parse_delay_level("");
140 assert!(result.is_err());
141 }
142
143 #[test]
144 fn parse_delay_level_with_millisecond_overflow() {
145 let result = StringUtils::parse_delay_level("9223372036854775807s");
146 assert!(result.is_err());
147 }
148
149 #[test]
150 fn parse_delay_level_with_max_valid_delay_time() {
151 let result = StringUtils::parse_delay_level("9223372036854775s").unwrap();
152 let (delay_level_table, max_delay_level) = result;
153 assert_eq!(delay_level_table[&1], i64::MAX - (i64::MAX % 1000));
154 assert_eq!(max_delay_level, 1);
155 }
156}