rocketmq_common/common/attribute/long_range_attribute.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 */
17
18/*
19 * Licensed to the Apache Software Foundation (ASF) under one or more
20 * contributor license agreements. See the NOTICE file distributed with
21 * this work for additional information regarding copyright ownership.
22 * The ASF licenses this file to You under the Apache License, Version 2.0
23 * (the "License"); you may not use this file except in compliance with
24 * the License. You may obtain a copy of the License at
25 *
26 * http://www.apache.org/licenses/LICENSE-2.0
27 *
28 * Unless required by applicable law or agreed to in writing, software
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
33 */
34use std::collections::HashSet;
35
36use cheetah_string::CheetahString;
37
38use crate::common::attribute::Attribute;
39use crate::common::attribute::AttributeBase;
40
41#[derive(Debug, Clone)]
42pub struct LongRangeAttribute {
43 attribute: AttributeBase,
44 /// Minimum allowed value (inclusive)
45 min: i64,
46
47 /// Maximum allowed value (inclusive)
48 max: i64,
49
50 /// Default value for this attribute
51 default_value: i64,
52}
53
54impl LongRangeAttribute {
55 /// Create a new enum attribute with the specified properties
56 ///
57 /// # Arguments
58 ///
59 /// * `name` - The name of the attribute
60 /// * `changeable` - Whether the attribute can be changed after creation
61 /// * `universe` - Set of valid values this attribute can take
62 /// * `default_value` - Default value for this attribute (must be in universe)
63 ///
64 /// # Returns
65 ///
66 /// A new EnumAttribute instance, or an error if the default value is not in the universe
67 pub fn new(
68 name: CheetahString,
69 changeable: bool,
70 min: i64,
71 max: i64,
72 default_value: i64,
73 ) -> Self {
74 Self {
75 attribute: AttributeBase::new(name, changeable),
76 min,
77 max,
78 default_value,
79 }
80 }
81
82 /// Get the default value for this attribute
83 #[inline]
84 pub fn default_value(&self) -> i64 {
85 self.default_value
86 }
87
88 /// Get the minimum allowed value
89 pub fn min(&self) -> i64 {
90 self.min
91 }
92
93 /// Get the maximum allowed value
94 pub fn max(&self) -> i64 {
95 self.max
96 }
97
98 /// Parse a string to a long integer
99 pub fn parse_long(value: &str) -> Result<i64, String> {
100 value
101 .parse::<i64>()
102 .map_err(|e| format!("Invalid integer format: {e}"))
103 }
104}
105
106impl Attribute for LongRangeAttribute {
107 fn verify(&self, value: &str) -> Result<(), String> {
108 // Parse the value to an i64
109 let parsed_value = Self::parse_long(value)?;
110
111 // Check if the value is in range
112 if parsed_value < self.min || parsed_value > self.max {
113 return Err(format!(
114 "Value {} is not in range [{}, {}]",
115 parsed_value, self.min, self.max
116 ));
117 }
118
119 Ok(())
120 }
121
122 #[inline]
123 fn name(&self) -> &CheetahString {
124 self.attribute.name()
125 }
126
127 #[inline]
128 fn is_changeable(&self) -> bool {
129 self.attribute.is_changeable()
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use cheetah_string::CheetahString;
136
137 use super::*;
138
139 #[test]
140 fn create_long_range_attribute() {
141 let name = CheetahString::from_static_str("test_attribute");
142 let attribute = LongRangeAttribute::new(name.clone(), true, 0, 100, 50);
143 assert_eq!(attribute.name(), &name);
144 assert!(attribute.is_changeable());
145 assert_eq!(attribute.default_value(), 50);
146 }
147
148 #[test]
149 fn parse_long_valid() {
150 let result = LongRangeAttribute::parse_long("42");
151 assert!(result.is_ok());
152 assert_eq!(result.unwrap(), 42);
153 }
154
155 #[test]
156 fn parse_long_invalid() {
157 let result = LongRangeAttribute::parse_long("invalid");
158 assert!(result.is_err());
159 assert_eq!(
160 result.unwrap_err(),
161 "Invalid integer format: invalid digit found in string"
162 );
163 }
164
165 #[test]
166 fn verify_value_in_range() {
167 let attribute = LongRangeAttribute::new(
168 CheetahString::from_static_str("test_attribute"),
169 true,
170 0,
171 100,
172 50,
173 );
174 let result = attribute.verify("42");
175 assert!(result.is_ok());
176 }
177
178 #[test]
179 fn verify_value_below_range() {
180 let attribute = LongRangeAttribute::new(
181 CheetahString::from_static_str("test_attribute"),
182 true,
183 0,
184 100,
185 50,
186 );
187 let result = attribute.verify("-1");
188 assert!(result.is_err());
189 assert_eq!(result.unwrap_err(), "Value -1 is not in range [0, 100]");
190 }
191
192 #[test]
193 fn verify_value_above_range() {
194 let attribute = LongRangeAttribute::new(
195 CheetahString::from_static_str("test_attribute"),
196 true,
197 0,
198 100,
199 50,
200 );
201 let result = attribute.verify("101");
202 assert!(result.is_err());
203 assert_eq!(result.unwrap_err(), "Value 101 is not in range [0, 100]");
204 }
205}