ic_storage/runtime/
custody.rs1use super::RuntimeConstructionError;
3use crate::{Memory, VectorMemory};
4use std::{rc::Rc, sync::Arc};
5
6#[cfg(test)]
7mod tests;
8
9#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
17pub struct BackingIdentity(usize);
18
19impl BackingIdentity {
20 #[must_use]
24 pub fn of_rc<T: ?Sized>(backing: &Rc<T>) -> Self {
25 Self(Rc::as_ptr(backing).cast::<()>() as usize)
26 }
27
28 #[must_use]
30 pub fn of_arc<T: ?Sized>(backing: &Arc<T>) -> Self {
31 Self(Arc::as_ptr(backing).cast::<()>() as usize)
32 }
33}
34
35pub trait MemoryBacking: Memory {
51 fn backing_identity(&self) -> BackingIdentity;
53}
54
55impl MemoryBacking for VectorMemory {
56 fn backing_identity(&self) -> BackingIdentity {
57 BackingIdentity::of_rc(self)
58 }
59}
60
61impl<M: MemoryBacking> MemoryBacking for Rc<M> {
62 fn backing_identity(&self) -> BackingIdentity {
63 self.as_ref().backing_identity()
64 }
65}
66
67#[cfg(target_arch = "wasm32")]
68impl MemoryBacking for crate::DefaultMemoryImpl {
69 fn backing_identity(&self) -> BackingIdentity {
70 BackingIdentity(0)
72 }
73}
74
75#[cfg(not(target_arch = "wasm32"))]
76static CLAIMS: std::sync::Mutex<Vec<BackingIdentity>> = std::sync::Mutex::new(Vec::new());
77
78#[cfg(target_arch = "wasm32")]
79thread_local! {
80 static CLAIMS: std::cell::RefCell<Vec<BackingIdentity>> = const {
81 std::cell::RefCell::new(Vec::new())
82 };
83}
84
85fn with_claims<T>(operation: impl FnOnce(&mut Vec<BackingIdentity>) -> T) -> T {
86 #[cfg(not(target_arch = "wasm32"))]
87 {
88 let mut claims = CLAIMS
89 .lock()
90 .unwrap_or_else(std::sync::PoisonError::into_inner);
91 operation(&mut claims)
92 }
93 #[cfg(target_arch = "wasm32")]
94 CLAIMS.with(|claims| operation(&mut claims.borrow_mut()))
95}
96
97pub(super) struct BackingClaim(BackingIdentity);
98
99impl BackingClaim {
100 pub fn acquire(memory: &impl MemoryBacking) -> Result<Self, RuntimeConstructionError> {
101 let identity = memory.backing_identity();
102 with_claims(|claims| match claims.binary_search(&identity) {
105 Ok(_) => Err(RuntimeConstructionError::BackingAlreadyClaimed),
106 Err(index) => {
107 claims.insert(index, identity);
108 Ok(Self(identity))
109 }
110 })
111 }
112}
113
114impl Drop for BackingClaim {
115 fn drop(&mut self) {
116 with_claims(|claims| {
117 if let Ok(index) = claims.binary_search(&self.0) {
118 claims.remove(index);
119 if claims.is_empty() {
120 *claims = Vec::new();
122 }
123 }
124 });
125 }
126}