Skip to main content

canic_core/ids/
subnet.rs

1use crate::{cdk::candid::CandidType, memory::impl_storable_bounded};
2use serde::{Deserialize, Serialize};
3use std::{borrow::Borrow, borrow::Cow, fmt, str::FromStr};
4
5///
6/// SubnetRole
7///
8/// A human-readable identifier for a subnet type
9///
10/// Stored as `Cow<'static, str>` so known constants can be zero‑copy while
11/// dynamic values allocate only when needed.
12///
13
14const PRIME_ROLE: &str = "prime";
15
16#[derive(
17    CandidType, Clone, Debug, Eq, Ord, PartialOrd, Deserialize, Serialize, PartialEq, Hash,
18)]
19#[serde(transparent)]
20pub struct SubnetRole(pub Cow<'static, str>);
21
22impl SubnetRole {
23    pub const PRIME: Self = Self(Cow::Borrowed(PRIME_ROLE));
24
25    #[must_use]
26    pub const fn new(s: &'static str) -> Self {
27        Self(Cow::Borrowed(s))
28    }
29
30    #[must_use]
31    pub const fn owned(s: String) -> Self {
32        Self(Cow::Owned(s))
33    }
34
35    #[must_use]
36    pub fn as_str(&self) -> &str {
37        &self.0
38    }
39
40    /// Returns true if this type represents the built-in PRIME subnet
41    #[must_use]
42    pub fn is_prime(&self) -> bool {
43        self.0.as_ref() == PRIME_ROLE
44    }
45
46    /// Convert into an owned string (avoids an extra allocation for owned variants).
47    #[must_use]
48    pub fn into_string(self) -> String {
49        self.0.into_owned()
50    }
51}
52
53impl FromStr for SubnetRole {
54    type Err = String;
55
56    fn from_str(s: &str) -> Result<Self, Self::Err> {
57        Ok(Self::owned(s.to_string()))
58    }
59}
60
61impl From<&'static str> for SubnetRole {
62    fn from(s: &'static str) -> Self {
63        Self(Cow::Borrowed(s))
64    }
65}
66
67impl From<&String> for SubnetRole {
68    fn from(s: &String) -> Self {
69        Self(Cow::Owned(s.clone()))
70    }
71}
72
73impl From<String> for SubnetRole {
74    fn from(s: String) -> Self {
75        Self(Cow::Owned(s))
76    }
77}
78
79impl From<SubnetRole> for String {
80    fn from(ct: SubnetRole) -> Self {
81        ct.into_string()
82    }
83}
84
85impl AsRef<str> for SubnetRole {
86    fn as_ref(&self) -> &str {
87        self.as_str()
88    }
89}
90
91impl Borrow<str> for SubnetRole {
92    fn borrow(&self) -> &str {
93        self.as_str()
94    }
95}
96
97impl fmt::Display for SubnetRole {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        f.write_str(self.as_str())
100    }
101}
102
103impl_storable_bounded!(SubnetRole, 64, false);
104
105///
106/// TESTS
107///
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn basic_traits_and_utils() {
115        let a = SubnetRole::PRIME;
116        assert!(a.is_prime());
117        assert_eq!(a.as_str(), "prime");
118        let b: SubnetRole = "example".into();
119        assert_eq!(b.as_str(), "example");
120        let s: String = b.clone().into();
121        assert_eq!(s, "example");
122        assert_eq!(b.as_ref(), "example");
123    }
124}