1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[repr(u8)]
7pub enum Role {
8 Blocked = 0,
10 None = 1,
12 Peer = 10,
14 Monitor = 20,
16 Operator = 30,
18 Admin = 40,
20}
21
22impl Role {
23 pub fn from_name(name: &str) -> Option<Self> {
25 match name.to_ascii_lowercase().as_str() {
26 "blocked" => Some(Self::Blocked),
27 "none" => Some(Self::None),
28 "peer" => Some(Self::Peer),
29 "monitor" => Some(Self::Monitor),
30 "operator" => Some(Self::Operator),
31 "admin" => Some(Self::Admin),
32 _ => Option::None,
33 }
34 }
35
36 pub fn as_str(self) -> &'static str {
38 match self {
39 Self::Blocked => "blocked",
40 Self::None => "none",
41 Self::Peer => "peer",
42 Self::Monitor => "monitor",
43 Self::Operator => "operator",
44 Self::Admin => "admin",
45 }
46 }
47
48 pub fn has_access(self) -> bool {
50 self >= Self::Peer
51 }
52}
53
54#[cfg(feature = "config")]
55impl<'de> serde::Deserialize<'de> for Role {
56 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
57 let s = String::deserialize(deserializer)?;
58 Self::from_name(&s).ok_or_else(|| serde::de::Error::unknown_variant(&s, ROLE_NAMES))
59 }
60}
61
62#[cfg(feature = "config")]
63impl serde::Serialize for Role {
64 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
65 serializer.serialize_str(self.as_str())
66 }
67}
68
69#[cfg(feature = "config")]
70const ROLE_NAMES: &[&str] = &["blocked", "none", "peer", "monitor", "operator", "admin"];
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn ordering() {
78 assert!(Role::Blocked < Role::None);
79 assert!(Role::None < Role::Peer);
80 assert!(Role::Peer < Role::Monitor);
81 assert!(Role::Monitor < Role::Operator);
82 assert!(Role::Operator < Role::Admin);
83 }
84
85 #[test]
86 fn from_name_case_insensitive() {
87 assert_eq!(Role::from_name("ADMIN"), Some(Role::Admin));
88 assert_eq!(Role::from_name("Peer"), Some(Role::Peer));
89 assert_eq!(Role::from_name("unknown"), Option::None);
90 }
91
92 #[test]
93 fn roundtrip_name() {
94 for role in
95 [Role::Blocked, Role::None, Role::Peer, Role::Monitor, Role::Operator, Role::Admin]
96 {
97 assert_eq!(Role::from_name(role.as_str()), Some(role));
98 }
99 }
100
101 #[test]
102 fn has_access() {
103 assert!(!Role::Blocked.has_access());
104 assert!(!Role::None.has_access());
105 assert!(Role::Peer.has_access());
106 assert!(Role::Monitor.has_access());
107 assert!(Role::Operator.has_access());
108 assert!(Role::Admin.has_access());
109 }
110}