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    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_type: Option<SubnetRole>,
46    pub subnet_pid: Option<Principal>,
47    pub root_pid: Option<Principal>,
48
49    // canister
50    pub canister_type: Option<CanisterRole>,
51    pub parent_pid: Option<Principal>,
52}
53
54impl_storable_bounded!(EnvData, 256, true);
55
56///
57/// Env
58///
59
60pub(crate) struct Env;
61
62impl Env {
63    // ---- Prime Root PID ----
64    #[must_use]
65    pub(crate) fn get_prime_root_pid() -> Option<Principal> {
66        ENV.with_borrow(|cell| cell.get().prime_root_pid)
67    }
68
69    pub(crate) fn set_prime_root_pid(pid: Principal) {
70        ENV.with_borrow_mut(|cell| {
71            let mut data = cell.get().clone();
72            data.prime_root_pid = Some(pid);
73            cell.set(data);
74        });
75    }
76
77    #[must_use]
78    pub(crate) fn is_prime_root() -> bool {
79        let prime_root_pid = Self::get_prime_root_pid();
80
81        prime_root_pid.is_some() && prime_root_pid == Self::get_root_pid()
82    }
83
84    // ---- Subnet Type ----
85    #[must_use]
86    pub(crate) fn get_subnet_type() -> Option<SubnetRole> {
87        ENV.with_borrow(|cell| cell.get().subnet_type.clone())
88    }
89
90    pub(crate) fn set_subnet_type(ty: SubnetRole) {
91        ENV.with_borrow_mut(|cell| {
92            let mut data = cell.get().clone();
93            data.subnet_type = Some(ty);
94            cell.set(data);
95        });
96    }
97
98    // ---- Subnet PID ----
99    #[must_use]
100    pub(crate) fn get_subnet_pid() -> Option<Principal> {
101        ENV.with_borrow(|cell| cell.get().subnet_pid)
102    }
103
104    pub(crate) fn set_subnet_pid(pid: Principal) {
105        ENV.with_borrow_mut(|cell| {
106            let mut data = cell.get().clone();
107            data.subnet_pid = Some(pid);
108            cell.set(data);
109        });
110    }
111
112    // ---- Root PID ----
113
114    #[must_use]
115    pub(crate) fn get_root_pid() -> Option<Principal> {
116        ENV.with_borrow(|cell| cell.get().root_pid)
117    }
118
119    pub(crate) fn set_root_pid(pid: Principal) {
120        ENV.with_borrow_mut(|cell| {
121            let mut data = cell.get().clone();
122            data.root_pid = Some(pid);
123            cell.set(data);
124        });
125    }
126
127    #[must_use]
128    pub(crate) fn is_root() -> bool {
129        Self::get_root_pid() == Some(canister_self())
130    }
131
132    // ---- Canister Type ----
133
134    #[must_use]
135    pub(crate) fn get_canister_type() -> Option<CanisterRole> {
136        ENV.with_borrow(|cell| cell.get().canister_type.clone())
137    }
138
139    /// Set/replace the current canister type.
140    pub(crate) fn set_canister_type(ty: CanisterRole) {
141        ENV.with_borrow_mut(|cell| {
142            let mut data = cell.get().clone();
143            data.canister_type = Some(ty);
144            cell.set(data);
145        });
146    }
147
148    // ---- Parent PID ----
149    #[must_use]
150    pub(crate) fn get_parent_pid() -> Option<Principal> {
151        ENV.with_borrow(|cell| cell.get().parent_pid)
152    }
153
154    // ---- Import / Export ----
155
156    /// Import a complete EnvData record, replacing any existing state.
157    pub(crate) fn import(data: EnvData) {
158        ENV.with_borrow_mut(|cell| {
159            cell.set(data);
160        });
161    }
162
163    #[must_use]
164    pub(crate) fn export() -> EnvData {
165        ENV.with_borrow(|cell| cell.get().clone())
166    }
167}