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}