Skip to main content

canic_core/ids/
canister.rs

1//! Module: ids::canister
2//!
3//! Responsibility: canister role identifiers shared across Canic layers.
4//! Does not own: role authorization policy or canister registry state.
5//! Boundary: provides stable, bounded role names for storage and DTOs.
6
7use crate::{cdk::candid::CandidType, impl_storable_bounded};
8use serde::{Deserialize, Serialize};
9use std::{
10    borrow::{Borrow, Cow},
11    fmt,
12    str::FromStr,
13};
14
15const ROOT_ROLE: &str = "root";
16const WASM_STORE_ROLE: &str = "wasm_store";
17
18///
19/// CanisterRole
20///
21/// Stable bounded canister role identifier.
22/// Owned by ids and shared across config, storage, DTOs, and workflows.
23///
24
25#[derive(
26    CandidType, Clone, Debug, Eq, Ord, PartialOrd, Deserialize, Serialize, PartialEq, Hash,
27)]
28#[serde(transparent)]
29pub struct CanisterRole(pub Cow<'static, str>);
30
31impl CanisterRole {
32    pub const ROOT: Self = Self(Cow::Borrowed(ROOT_ROLE));
33    pub const WASM_STORE: Self = Self(Cow::Borrowed(WASM_STORE_ROLE));
34
35    /// Create a borrowed static canister role.
36    #[must_use]
37    pub const fn new(s: &'static str) -> Self {
38        Self(Cow::Borrowed(s))
39    }
40
41    /// Create an owned canister role.
42    #[must_use]
43    pub const fn owned(s: String) -> Self {
44        Self(Cow::Owned(s))
45    }
46
47    /// Return the canister role as text.
48    #[must_use]
49    pub fn as_str(&self) -> &str {
50        &self.0
51    }
52
53    /// Return whether this role is the built-in root role.
54    #[must_use]
55    pub fn is_root(&self) -> bool {
56        self.0.as_ref() == ROOT_ROLE
57    }
58
59    /// Return whether this role is the built-in wasm-store role.
60    #[must_use]
61    pub fn is_wasm_store(&self) -> bool {
62        self.0.as_ref() == WASM_STORE_ROLE
63    }
64
65    /// Convert the role into an owned string.
66    #[must_use]
67    pub fn into_string(self) -> String {
68        self.0.into_owned()
69    }
70}
71
72impl FromStr for CanisterRole {
73    type Err = String;
74
75    fn from_str(s: &str) -> Result<Self, Self::Err> {
76        Ok(Self::owned(s.to_string()))
77    }
78}
79
80impl From<&'static str> for CanisterRole {
81    fn from(s: &'static str) -> Self {
82        Self(Cow::Borrowed(s))
83    }
84}
85
86impl From<&String> for CanisterRole {
87    fn from(s: &String) -> Self {
88        Self(Cow::Owned(s.clone()))
89    }
90}
91
92impl From<String> for CanisterRole {
93    fn from(s: String) -> Self {
94        Self(Cow::Owned(s))
95    }
96}
97
98impl From<CanisterRole> for String {
99    fn from(role: CanisterRole) -> Self {
100        role.into_string()
101    }
102}
103
104impl AsRef<str> for CanisterRole {
105    fn as_ref(&self) -> &str {
106        self.as_str()
107    }
108}
109
110impl Borrow<str> for CanisterRole {
111    fn borrow(&self) -> &str {
112        self.as_str()
113    }
114}
115
116impl fmt::Display for CanisterRole {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        f.write_str(self.as_str())
119    }
120}
121
122impl_storable_bounded!(CanisterRole, 64, false);