canic_core/model/memory/
env.rs

1use crate::{
2    cdk::{
3        api::canister_self,
4        structures::{DefaultMemoryImpl, cell::Cell, memory::VirtualMemory},
5    },
6    eager_static, ic_memory,
7    ids::{CanisterRole, SubnetRole},
8    memory::impl_storable_bounded,
9    model::memory::id::ENV_ID,
10};
11use candid::{CandidType, Principal};
12use serde::{Deserialize, Serialize};
13use std::cell::RefCell;
14
15//
16// ENV
17// All the environment variables a canister needs
18//
19
20eager_static! {
21    static ENV: RefCell<Cell<EnvData, VirtualMemory<DefaultMemoryImpl>>> =
22        RefCell::new(Cell::init(
23            ic_memory!(EnvData, ENV_ID),
24            EnvData::default(),
25        ));
26}
27
28///
29/// EnvData
30///
31/// `prime_root_pid` : passed to the root during install arguments.
32/// `parent_pid`     : passed to the root during install arguments.
33///
34/// All other fields are derived during install/upgrade and cached locally so
35/// every canister can answer questions about its environment without touching
36/// global state.
37///
38
39#[derive(CandidType, Clone, Debug, Default, Deserialize, Serialize)]
40pub struct EnvData {
41    // app
42    pub prime_root_pid: Option<Principal>,
43
44    // subnet
45    pub subnet_role: Option<SubnetRole>,
46    pub subnet_pid: Option<Principal>,
47    pub root_pid: Option<Principal>,
48
49    // canister
50    pub canister_role: Option<CanisterRole>,
51    pub parent_pid: Option<Principal>,
52}
53
54impl_storable_bounded!(EnvData, 256, true);
55
56///
57/// Env
58///
59
60pub struct Env;
61
62impl Env {
63    //
64    // ---- Prime Root PID ----
65    //
66
67    #[must_use]
68    pub(crate) fn get_prime_root_pid() -> Option<Principal> {
69        ENV.with_borrow(|cell| cell.get().prime_root_pid)
70    }
71
72    pub(crate) fn set_prime_root_pid(pid: Principal) {
73        ENV.with_borrow_mut(|cell| {
74            let mut data = cell.get().clone();
75            data.prime_root_pid = Some(pid);
76            cell.set(data);
77        });
78    }
79
80    #[must_use]
81    pub(crate) fn is_prime_root() -> bool {
82        let prime_root_pid = Self::get_prime_root_pid();
83
84        prime_root_pid.is_some() && prime_root_pid == Self::get_root_pid()
85    }
86
87    //
88    // ---- Subnet Type ----
89    //
90
91    #[must_use]
92    pub(crate) fn get_subnet_role() -> Option<SubnetRole> {
93        ENV.with_borrow(|cell| cell.get().subnet_role.clone())
94    }
95
96    pub(crate) fn set_subnet_role(role: SubnetRole) {
97        ENV.with_borrow_mut(|cell| {
98            let mut data = cell.get().clone();
99            data.subnet_role = Some(role);
100            cell.set(data);
101        });
102    }
103
104    #[must_use]
105    pub(crate) fn is_prime_subnet() -> bool {
106        Self::get_subnet_role().is_some_and(|r| r.is_prime())
107    }
108
109    //
110    // ---- Subnet PID ----
111    //
112
113    #[must_use]
114    pub(crate) fn get_subnet_pid() -> Option<Principal> {
115        ENV.with_borrow(|cell| cell.get().subnet_pid)
116    }
117
118    pub(crate) fn set_subnet_pid(pid: Principal) {
119        ENV.with_borrow_mut(|cell| {
120            let mut data = cell.get().clone();
121            data.subnet_pid = Some(pid);
122            cell.set(data);
123        });
124    }
125
126    //
127    // ---- Root PID ----
128    //
129
130    #[must_use]
131    pub(crate) fn get_root_pid() -> Option<Principal> {
132        ENV.with_borrow(|cell| cell.get().root_pid)
133    }
134
135    pub(crate) fn set_root_pid(pid: Principal) {
136        ENV.with_borrow_mut(|cell| {
137            let mut data = cell.get().clone();
138            data.root_pid = Some(pid);
139            cell.set(data);
140        });
141    }
142
143    #[must_use]
144    pub(crate) fn is_root() -> bool {
145        Self::get_root_pid() == Some(canister_self())
146    }
147
148    //
149    // ---- Canister Type ----
150    //
151
152    #[must_use]
153    pub(crate) fn get_canister_role() -> Option<CanisterRole> {
154        ENV.with_borrow(|cell| cell.get().canister_role.clone())
155    }
156
157    /// Set/replace the current canister role.
158    pub(crate) fn set_canister_role(role: CanisterRole) {
159        ENV.with_borrow_mut(|cell| {
160            let mut data = cell.get().clone();
161            data.canister_role = Some(role);
162            cell.set(data);
163        });
164    }
165
166    //
167    // ---- Parent PID ----
168    //
169
170    #[must_use]
171    pub(crate) fn get_parent_pid() -> Option<Principal> {
172        ENV.with_borrow(|cell| cell.get().parent_pid)
173    }
174
175    //
176    // ---- Import / Export ----
177    //
178
179    /// Import a complete EnvData record, replacing any existing state.
180    pub(crate) fn import(data: EnvData) {
181        ENV.with_borrow_mut(|cell| {
182            cell.set(data);
183        });
184    }
185
186    #[must_use]
187    pub(crate) fn export() -> EnvData {
188        ENV.with_borrow(|cell| cell.get().clone())
189    }
190}