#[cfg(test)]
mod tests;
use ic_memory::{DefaultMemoryImpl, MemoryRuntime, RuntimeMemory, RuntimeOpenError};
use std::{cell::OnceCell, rc::Rc};
thread_local! {
static MEMORY_RUNTIME: OnceCell<Rc<MemoryRuntime<DefaultMemoryImpl>>> = const { OnceCell::new() };
}
#[derive(Clone, Copy, Debug, Eq, thiserror::Error, PartialEq)]
pub enum MemoryRuntimeBindingError {
#[error("memory runtime has not completed bootstrap")]
NotBootstrapped,
#[error("IcyDB is already bound to a different memory runtime")]
AlreadyBound,
}
pub fn bind_memory_runtime(
runtime: Rc<MemoryRuntime<DefaultMemoryImpl>>,
) -> Result<(), MemoryRuntimeBindingError> {
if !runtime.is_bootstrapped() {
return Err(MemoryRuntimeBindingError::NotBootstrapped);
}
MEMORY_RUNTIME.with(|bound| {
if let Some(existing) = bound.get() {
return if Rc::ptr_eq(existing, &runtime) {
Ok(())
} else {
Err(MemoryRuntimeBindingError::AlreadyBound)
};
}
bound
.set(runtime)
.map_err(|_| MemoryRuntimeBindingError::AlreadyBound)
})
}
#[must_use]
pub fn memory_runtime() -> Option<Rc<MemoryRuntime<DefaultMemoryImpl>>> {
MEMORY_RUNTIME.with(|bound| bound.get().cloned())
}
#[doc(hidden)]
pub fn open_memory(stable_key: &str) -> Result<RuntimeMemory<DefaultMemoryImpl>, RuntimeOpenError> {
memory_runtime()
.ok_or(RuntimeOpenError::NotBootstrapped)?
.open_memory(stable_key)
}