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