Skip to main content

rocketmq_security_api/
resource_type.rs

1// Copyright 2023 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 serde::Deserialize;
16use serde::Deserializer;
17use serde::Serialize;
18use serde::Serializer;
19
20#[derive(Debug, Copy, Clone, Eq, PartialEq)]
21#[repr(u8)]
22/// Identifies the resource type state.
23pub enum ResourceType {
24    /// Represents the unknown case.
25    Unknown = 0,
26    /// Represents the any case.
27    Any = 1,
28    /// Represents the cluster case.
29    Cluster = 2,
30    /// Represents the namespace case.
31    Namespace = 3,
32    /// Represents the topic case.
33    Topic = 4,
34    /// Represents the group case.
35    Group = 5,
36}
37
38impl ResourceType {
39    /// Returns by name.
40    pub fn get_by_name(name: &str) -> Option<Self> {
41        if name.eq_ignore_ascii_case("Unknown") {
42            Some(Self::Unknown)
43        } else if name.eq_ignore_ascii_case("Any") {
44            Some(Self::Any)
45        } else if name.eq_ignore_ascii_case("Cluster") {
46            Some(Self::Cluster)
47        } else if name.eq_ignore_ascii_case("Namespace") {
48            Some(Self::Namespace)
49        } else if name.eq_ignore_ascii_case("Topic") {
50            Some(Self::Topic)
51        } else if name.eq_ignore_ascii_case("Group") {
52            Some(Self::Group)
53        } else {
54            None
55        }
56    }
57
58    #[inline]
59    /// Returns the code.
60    pub fn code(self) -> u8 {
61        self as u8
62    }
63
64    #[inline]
65    /// Returns the name.
66    pub fn name(self) -> &'static str {
67        match self {
68            Self::Unknown => "Unknown",
69            Self::Any => "Any",
70            Self::Cluster => "Cluster",
71            Self::Namespace => "Namespace",
72            Self::Topic => "Topic",
73            Self::Group => "Group",
74        }
75    }
76}
77
78impl Serialize for ResourceType {
79    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: Serializer,
82    {
83        serializer.serialize_u8(self.code())
84    }
85}
86
87impl<'de> Deserialize<'de> for ResourceType {
88    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89    where
90        D: Deserializer<'de>,
91    {
92        let v = u8::deserialize(deserializer)?;
93        match v {
94            0 => Ok(ResourceType::Unknown),
95            1 => Ok(ResourceType::Any),
96            2 => Ok(ResourceType::Cluster),
97            3 => Ok(ResourceType::Namespace),
98            4 => Ok(ResourceType::Topic),
99            5 => Ok(ResourceType::Group),
100            _ => Err(serde::de::Error::custom("invalid ResourceType code")),
101        }
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_get_by_name() {
111        assert_eq!(ResourceType::get_by_name("Unknown"), Some(ResourceType::Unknown));
112        assert_eq!(ResourceType::get_by_name("Any"), Some(ResourceType::Any));
113        assert_eq!(ResourceType::get_by_name("Cluster"), Some(ResourceType::Cluster));
114        assert_eq!(ResourceType::get_by_name("Namespace"), Some(ResourceType::Namespace));
115        assert_eq!(ResourceType::get_by_name("Topic"), Some(ResourceType::Topic));
116        assert_eq!(ResourceType::get_by_name("TOPIC"), Some(ResourceType::Topic));
117        assert_eq!(ResourceType::get_by_name("ToPiC"), Some(ResourceType::Topic));
118        assert_eq!(ResourceType::get_by_name("GROUP"), Some(ResourceType::Group));
119        assert_eq!(ResourceType::get_by_name("Group"), Some(ResourceType::Group));
120        assert_eq!(ResourceType::get_by_name("Invalid"), None);
121    }
122
123    #[test]
124    fn test_code() {
125        assert_eq!(ResourceType::Unknown.code(), 0);
126        assert_eq!(ResourceType::Any.code(), 1);
127        assert_eq!(ResourceType::Cluster.code(), 2);
128        assert_eq!(ResourceType::Namespace.code(), 3);
129        assert_eq!(ResourceType::Topic.code(), 4);
130        assert_eq!(ResourceType::Group.code(), 5);
131    }
132
133    #[test]
134    fn test_name() {
135        assert_eq!(ResourceType::Unknown.name(), "Unknown");
136        assert_eq!(ResourceType::Any.name(), "Any");
137        assert_eq!(ResourceType::Cluster.name(), "Cluster");
138        assert_eq!(ResourceType::Namespace.name(), "Namespace");
139        assert_eq!(ResourceType::Topic.name(), "Topic");
140        assert_eq!(ResourceType::Group.name(), "Group");
141    }
142
143    #[test]
144    fn test_serialize_to_json() {
145        let unknown = ResourceType::Unknown;
146        let json = serde_json::to_string(&unknown).unwrap();
147        assert_eq!(json, "0");
148
149        let any = ResourceType::Any;
150        let json = serde_json::to_string(&any).unwrap();
151        assert_eq!(json, "1");
152
153        let topic = ResourceType::Topic;
154        let json = serde_json::to_string(&topic).unwrap();
155        assert_eq!(json, "4");
156
157        let group = ResourceType::Group;
158        let json = serde_json::to_string(&group).unwrap();
159        assert_eq!(json, "5");
160    }
161
162    #[test]
163    fn test_deserialize_from_json() {
164        let json = "0";
165        let resource: ResourceType = serde_json::from_str(json).unwrap();
166        assert_eq!(resource, ResourceType::Unknown);
167
168        let json = "3";
169        let resource: ResourceType = serde_json::from_str(json).unwrap();
170        assert_eq!(resource, ResourceType::Namespace);
171
172        let json = "5";
173        let resource: ResourceType = serde_json::from_str(json).unwrap();
174        assert_eq!(resource, ResourceType::Group);
175    }
176
177    #[test]
178    fn test_serialize_deserialize_round_trip() {
179        let variants = vec![
180            ResourceType::Unknown,
181            ResourceType::Any,
182            ResourceType::Cluster,
183            ResourceType::Namespace,
184            ResourceType::Topic,
185            ResourceType::Group,
186        ];
187
188        for original in variants {
189            // Serialize to JSON
190            let json = serde_json::to_string(&original).unwrap();
191
192            // Deserialize back from JSON
193            let deserialized: ResourceType = serde_json::from_str(&json).unwrap();
194
195            // Should match the original
196            assert_eq!(original, deserialized);
197        }
198    }
199
200    #[test]
201    fn test_deserialize_invalid_code() {
202        // Test invalid codes
203        for invalid_code in ["6", "99", "255"] {
204            let result: Result<ResourceType, _> = serde_json::from_str(invalid_code);
205            assert!(result.is_err());
206            let err = result.unwrap_err();
207            let err_msg = err.to_string();
208            assert!(err_msg.contains("invalid ResourceType code"));
209        }
210    }
211
212    #[test]
213    fn test_serialize_all_variants() {
214        let test_cases = vec![
215            (ResourceType::Unknown, "0"),
216            (ResourceType::Any, "1"),
217            (ResourceType::Cluster, "2"),
218            (ResourceType::Namespace, "3"),
219            (ResourceType::Topic, "4"),
220            (ResourceType::Group, "5"),
221        ];
222
223        for (resource_type, expected_json) in test_cases {
224            let json = serde_json::to_string(&resource_type).unwrap();
225            assert_eq!(json, expected_json);
226        }
227    }
228}