canic_core/ids/
subnet.rs

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