canic_core/ops/runtime/
wasm.rs1use crate::{
2 Error, ThisError, cdk::types::WasmModule, ids::CanisterRole, log, log::Topic,
3 ops::runtime::RuntimeOpsError,
4};
5use std::{cell::RefCell, collections::HashMap};
6
7thread_local! {
8 static WASM_REGISTRY: RefCell<HashMap<CanisterRole, WasmModule>> =
16 RefCell::new(HashMap::new());
17}
18
19#[derive(Debug, ThisError)]
24pub enum WasmOpsError {
25 #[error("wasm '{0}' not found")]
26 WasmNotFound(CanisterRole),
27}
28
29impl From<WasmOpsError> for Error {
30 fn from(err: WasmOpsError) -> Self {
31 RuntimeOpsError::WasmOpsError(err).into()
32 }
33}
34
35pub struct WasmOps;
41
42impl WasmOps {
43 #[must_use]
45 pub fn get(role: &CanisterRole) -> Option<WasmModule> {
46 WASM_REGISTRY.with_borrow(|reg| reg.get(role).cloned())
47 }
48
49 pub fn try_get(role: &CanisterRole) -> Result<WasmModule, Error> {
51 Self::get(role).ok_or_else(|| WasmOpsError::WasmNotFound(role.clone()).into())
52 }
53
54 #[allow(clippy::cast_precision_loss)]
58 pub fn import_static(wasms: &'static [(CanisterRole, &[u8])]) {
59 for (role, bytes) in wasms {
60 let wasm = WasmModule::new(bytes);
61 let size = wasm.len();
62
63 WASM_REGISTRY.with_borrow_mut(|reg| {
64 reg.insert(role.clone(), wasm);
65 });
66
67 log!(
68 Topic::Wasm,
69 Info,
70 "📄 wasm.import: {} ({:.2} KB)",
71 role,
72 size as f64 / 1000.0
73 );
74 }
75 }
76
77 pub fn import_static_quiet(wasms: &'static [(CanisterRole, &[u8])]) {
79 for (role, bytes) in wasms {
80 let wasm = WasmModule::new(bytes);
81 WASM_REGISTRY.with_borrow_mut(|reg| {
82 reg.insert(role.clone(), wasm);
83 });
84 }
85 }
86
87 #[cfg(test)]
89 #[expect(dead_code)]
90 pub(crate) fn clear_for_test() {
91 WASM_REGISTRY.with_borrow_mut(HashMap::clear);
92 }
93}