Skip to main content

rocketmq_model/common/attribute/
subscription_group_attributes.rs

1// Copyright 2026 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::HashMap;
16use std::collections::HashSet;
17use std::sync::Arc;
18use std::sync::OnceLock;
19
20use cheetah_string::CheetahString;
21
22use crate::common::attribute::bool_attribute::BooleanAttribute;
23use crate::common::attribute::enum_attribute::EnumAttribute;
24use crate::common::attribute::long_range_attribute::LongRangeAttribute;
25use crate::common::attribute::string_attribute::StringAttribute;
26use crate::common::attribute::Attribute;
27
28pub const LITE_BIND_TOPIC_ATTRIBUTE_NAME: &str = "lite.bind.topic";
29pub const LITE_SUB_MODEL_ATTRIBUTE_NAME: &str = "lite.sub.model";
30pub const LITE_SUB_RESET_OFFSET_EXCLUSIVE_ATTRIBUTE_NAME: &str = "lite.sub.reset.offset.exclusive";
31pub const LITE_SUB_RESET_OFFSET_UNSUBSCRIBE_ATTRIBUTE_NAME: &str = "lite.sub.reset.offset.unsubscribe";
32pub const LITE_SUB_CLIENT_QUOTA_ATTRIBUTE_NAME: &str = "lite.sub.client.quota";
33pub const LITE_SUB_CLIENT_MAX_EVENT_COUNT_ATTRIBUTE_NAME: &str = "lite.sub.client.max.event.cnt";
34pub const LITE_SUB_WILDCARD_ATTRIBUTE_NAME: &str = "lite.sub.wildcard";
35pub const PRIORITY_FACTOR_ATTRIBUTE_NAME: &str = "priority.factor";
36
37pub struct SubscriptionGroupAttributes {}
38
39impl SubscriptionGroupAttributes {
40    pub fn lite_bind_topic_attribute() -> &'static StringAttribute {
41        static INSTANCE: OnceLock<StringAttribute> = OnceLock::new();
42        INSTANCE
43            .get_or_init(|| StringAttribute::new(CheetahString::from_static_str(LITE_BIND_TOPIC_ATTRIBUTE_NAME), true))
44    }
45
46    pub fn lite_sub_model_attribute() -> &'static EnumAttribute {
47        static INSTANCE: OnceLock<EnumAttribute> = OnceLock::new();
48        INSTANCE.get_or_init(|| {
49            let mut valid_values = HashSet::new();
50            valid_values.insert(CheetahString::from_static_str("Shared"));
51            valid_values.insert(CheetahString::from_static_str("Exclusive"));
52            EnumAttribute::new(
53                CheetahString::from_static_str(LITE_SUB_MODEL_ATTRIBUTE_NAME),
54                true,
55                valid_values,
56                CheetahString::from_static_str("Shared"),
57            )
58        })
59    }
60
61    pub fn lite_sub_reset_offset_exclusive_attribute() -> &'static BooleanAttribute {
62        static INSTANCE: OnceLock<BooleanAttribute> = OnceLock::new();
63        INSTANCE.get_or_init(|| {
64            BooleanAttribute::new(
65                CheetahString::from_static_str(LITE_SUB_RESET_OFFSET_EXCLUSIVE_ATTRIBUTE_NAME),
66                true,
67                false,
68            )
69        })
70    }
71
72    pub fn lite_sub_reset_offset_unsubscribe_attribute() -> &'static BooleanAttribute {
73        static INSTANCE: OnceLock<BooleanAttribute> = OnceLock::new();
74        INSTANCE.get_or_init(|| {
75            BooleanAttribute::new(
76                CheetahString::from_static_str(LITE_SUB_RESET_OFFSET_UNSUBSCRIBE_ATTRIBUTE_NAME),
77                true,
78                false,
79            )
80        })
81    }
82
83    pub fn lite_sub_client_quota_attribute() -> &'static LongRangeAttribute {
84        static INSTANCE: OnceLock<LongRangeAttribute> = OnceLock::new();
85        INSTANCE.get_or_init(|| {
86            LongRangeAttribute::new(
87                CheetahString::from_static_str(LITE_SUB_CLIENT_QUOTA_ATTRIBUTE_NAME),
88                true,
89                -1,
90                i64::MAX,
91                2000,
92            )
93        })
94    }
95
96    pub fn lite_sub_client_max_event_count_attribute() -> &'static LongRangeAttribute {
97        static INSTANCE: OnceLock<LongRangeAttribute> = OnceLock::new();
98        INSTANCE.get_or_init(|| {
99            LongRangeAttribute::new(
100                CheetahString::from_static_str(LITE_SUB_CLIENT_MAX_EVENT_COUNT_ATTRIBUTE_NAME),
101                true,
102                10,
103                i64::MAX,
104                400,
105            )
106        })
107    }
108
109    pub fn lite_sub_wildcard_attribute() -> &'static StringAttribute {
110        static INSTANCE: OnceLock<StringAttribute> = OnceLock::new();
111        INSTANCE.get_or_init(|| {
112            StringAttribute::new(CheetahString::from_static_str(LITE_SUB_WILDCARD_ATTRIBUTE_NAME), true)
113        })
114    }
115
116    pub fn priority_factor_attribute() -> &'static LongRangeAttribute {
117        static INSTANCE: OnceLock<LongRangeAttribute> = OnceLock::new();
118        INSTANCE.get_or_init(|| {
119            LongRangeAttribute::new(
120                CheetahString::from_static_str(PRIORITY_FACTOR_ATTRIBUTE_NAME),
121                true,
122                0,
123                100,
124                100,
125            )
126        })
127    }
128
129    #[allow(clippy::redundant_closure)]
130    pub fn all() -> &'static HashMap<CheetahString, Arc<dyn Attribute>> {
131        static ALL: OnceLock<HashMap<CheetahString, Arc<dyn Attribute>>> = OnceLock::new();
132        ALL.get_or_init(|| {
133            let mut all = HashMap::new();
134            let lite_bind_topic = Self::lite_bind_topic_attribute();
135            let lite_sub_model = Self::lite_sub_model_attribute();
136            let lite_sub_reset_offset_exclusive = Self::lite_sub_reset_offset_exclusive_attribute();
137            let lite_sub_reset_offset_unsubscribe = Self::lite_sub_reset_offset_unsubscribe_attribute();
138            let lite_sub_client_quota = Self::lite_sub_client_quota_attribute();
139            let lite_sub_client_max_event_count = Self::lite_sub_client_max_event_count_attribute();
140            let lite_sub_wildcard = Self::lite_sub_wildcard_attribute();
141            let priority_factor = Self::priority_factor_attribute();
142
143            all.insert(
144                lite_bind_topic.name().clone(),
145                Arc::new(lite_bind_topic.clone()) as Arc<dyn Attribute>,
146            );
147            all.insert(
148                lite_sub_model.name().clone(),
149                Arc::new(lite_sub_model.clone()) as Arc<dyn Attribute>,
150            );
151            all.insert(
152                lite_sub_reset_offset_exclusive.name().clone(),
153                Arc::new(lite_sub_reset_offset_exclusive.clone()) as Arc<dyn Attribute>,
154            );
155            all.insert(
156                lite_sub_reset_offset_unsubscribe.name().clone(),
157                Arc::new(lite_sub_reset_offset_unsubscribe.clone()) as Arc<dyn Attribute>,
158            );
159            all.insert(
160                lite_sub_client_quota.name().clone(),
161                Arc::new(lite_sub_client_quota.clone()) as Arc<dyn Attribute>,
162            );
163            all.insert(
164                lite_sub_client_max_event_count.name().clone(),
165                Arc::new(lite_sub_client_max_event_count.clone()) as Arc<dyn Attribute>,
166            );
167            all.insert(
168                lite_sub_wildcard.name().clone(),
169                Arc::new(lite_sub_wildcard.clone()) as Arc<dyn Attribute>,
170            );
171            all.insert(
172                priority_factor.name().clone(),
173                Arc::new(priority_factor.clone()) as Arc<dyn Attribute>,
174            );
175
176            all
177        })
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    #[test]
186    fn all_contains_lite_bind_topic_attribute() {
187        let all = SubscriptionGroupAttributes::all();
188
189        assert!(all.contains_key(&CheetahString::from_static_str(LITE_BIND_TOPIC_ATTRIBUTE_NAME)));
190        assert!(all.contains_key(&CheetahString::from_static_str(LITE_SUB_MODEL_ATTRIBUTE_NAME)));
191        assert!(all.contains_key(&CheetahString::from_static_str(
192            LITE_SUB_RESET_OFFSET_EXCLUSIVE_ATTRIBUTE_NAME
193        )));
194        assert!(all.contains_key(&CheetahString::from_static_str(
195            LITE_SUB_RESET_OFFSET_UNSUBSCRIBE_ATTRIBUTE_NAME
196        )));
197        assert!(all.contains_key(&CheetahString::from_static_str(LITE_SUB_CLIENT_QUOTA_ATTRIBUTE_NAME)));
198        assert!(all.contains_key(&CheetahString::from_static_str(
199            LITE_SUB_CLIENT_MAX_EVENT_COUNT_ATTRIBUTE_NAME
200        )));
201        assert!(all.contains_key(&CheetahString::from_static_str(LITE_SUB_WILDCARD_ATTRIBUTE_NAME)));
202        assert!(all.contains_key(&CheetahString::from_static_str(PRIORITY_FACTOR_ATTRIBUTE_NAME)));
203    }
204
205    #[test]
206    fn lite_sub_model_attribute_uses_java_defaults() {
207        let attribute = SubscriptionGroupAttributes::lite_sub_model_attribute();
208
209        assert_eq!(attribute.default_value(), "Shared");
210        assert!(attribute.universe().contains(&CheetahString::from_static_str("Shared")));
211        assert!(attribute
212            .universe()
213            .contains(&CheetahString::from_static_str("Exclusive")));
214    }
215
216    #[test]
217    fn lite_sub_reset_offset_attributes_default_to_false() {
218        let exclusive = SubscriptionGroupAttributes::lite_sub_reset_offset_exclusive_attribute();
219        let unsubscribe = SubscriptionGroupAttributes::lite_sub_reset_offset_unsubscribe_attribute();
220
221        assert!(!exclusive.default_value());
222        assert!(!unsubscribe.default_value());
223    }
224
225    #[test]
226    fn lite_sub_client_quota_attribute_uses_java_defaults() {
227        let attribute = SubscriptionGroupAttributes::lite_sub_client_quota_attribute();
228
229        assert_eq!(attribute.default_value(), 2000);
230        assert_eq!(attribute.min(), -1);
231        assert_eq!(attribute.max(), i64::MAX);
232    }
233
234    #[test]
235    fn lite_sub_client_max_event_count_attribute_uses_java_defaults() {
236        let attribute = SubscriptionGroupAttributes::lite_sub_client_max_event_count_attribute();
237
238        assert_eq!(attribute.default_value(), 400);
239        assert_eq!(attribute.min(), 10);
240        assert_eq!(attribute.max(), i64::MAX);
241    }
242
243    #[test]
244    fn priority_factor_attribute_uses_business_compatible_defaults() {
245        let attribute = SubscriptionGroupAttributes::priority_factor_attribute();
246
247        assert_eq!(attribute.default_value(), 100);
248        assert_eq!(attribute.min(), 0);
249        assert_eq!(attribute.max(), 100);
250    }
251}