ic_memory/runtime/
custody.rs1use super::RuntimeConstructionError;
3use ic_platform::stable_structures::{Memory, VectorMemory};
4use std::{collections::BTreeSet, rc::Rc, sync::Arc};
5
6#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
14pub struct BackingIdentity(usize);
15
16impl BackingIdentity {
17 #[must_use]
21 pub fn of_rc<T: ?Sized>(backing: &Rc<T>) -> Self {
22 Self(Rc::as_ptr(backing).cast::<()>() as usize)
23 }
24
25 #[must_use]
27 pub fn of_arc<T: ?Sized>(backing: &Arc<T>) -> Self {
28 Self(Arc::as_ptr(backing).cast::<()>() as usize)
29 }
30}
31
32pub trait MemoryBacking: Memory {
48 fn backing_identity(&self) -> BackingIdentity;
50}
51
52impl MemoryBacking for VectorMemory {
53 fn backing_identity(&self) -> BackingIdentity {
54 BackingIdentity::of_rc(self)
55 }
56}
57
58impl<M: MemoryBacking> MemoryBacking for Rc<M> {
59 fn backing_identity(&self) -> BackingIdentity {
60 self.as_ref().backing_identity()
61 }
62}
63
64#[cfg(target_arch = "wasm32")]
65impl MemoryBacking for ic_platform::stable_structures::DefaultMemoryImpl {
66 fn backing_identity(&self) -> BackingIdentity {
67 BackingIdentity(0)
69 }
70}
71
72#[cfg(not(target_arch = "wasm32"))]
73static CLAIMS: std::sync::Mutex<BTreeSet<BackingIdentity>> = std::sync::Mutex::new(BTreeSet::new());
74
75#[cfg(target_arch = "wasm32")]
76thread_local! {
77 static CLAIMS: std::cell::RefCell<BTreeSet<BackingIdentity>> = const {
78 std::cell::RefCell::new(BTreeSet::new())
79 };
80}
81
82fn with_claims<T>(operation: impl FnOnce(&mut BTreeSet<BackingIdentity>) -> T) -> T {
83 #[cfg(not(target_arch = "wasm32"))]
84 {
85 let mut claims = CLAIMS
86 .lock()
87 .unwrap_or_else(std::sync::PoisonError::into_inner);
88 operation(&mut claims)
89 }
90 #[cfg(target_arch = "wasm32")]
91 CLAIMS.with(|claims| operation(&mut claims.borrow_mut()))
92}
93
94pub(super) struct BackingClaim(BackingIdentity);
95
96impl BackingClaim {
97 pub fn acquire(memory: &impl MemoryBacking) -> Result<Self, RuntimeConstructionError> {
98 let identity = memory.backing_identity();
99 if with_claims(|claims| claims.insert(identity)) {
100 Ok(Self(identity))
101 } else {
102 Err(RuntimeConstructionError::BackingAlreadyClaimed)
103 }
104 }
105}
106
107impl Drop for BackingClaim {
108 fn drop(&mut self) {
109 with_claims(|claims| claims.remove(&self.0));
110 }
111}
112
113#[cfg(all(test, not(target_arch = "wasm32")))]
114impl<M: MemoryBacking> MemoryBacking for ic_testkit_native::memory::MeteredMemory<M> {
115 fn backing_identity(&self) -> BackingIdentity {
116 self.backing().backing_identity()
117 }
118}