use std::cell::RefCell;
use ic_stable_structures::{memory_manager::MemoryManager, DefaultMemoryImpl};
pub type VirtualMemory =
ic_stable_structures::memory_manager::VirtualMemory<ic_stable_structures::DefaultMemoryImpl>;
pub use ic_stable_structures::memory_manager::MemoryId;
pub use ic_stable_structures::storable::Bound;
pub use ic_stable_structures::writer::Writer;
pub use ic_stable_structures::Memory;
pub use ic_stable_structures::Storable;
pub use std::borrow::Cow;
pub type StableCell<T> = ic_stable_structures::Cell<T, VirtualMemory>;
pub type StableVec<T> = ic_stable_structures::Vec<T, VirtualMemory>;
pub type StableBTreeMap<K, V> = ic_stable_structures::BTreeMap<K, V, VirtualMemory>;
pub type StableLog<T> = ic_stable_structures::Log<T, VirtualMemory, VirtualMemory>;
pub type StablePriorityQueue<T> = ic_stable_structures::MinHeap<T, VirtualMemory>;
thread_local! {
static MEMORY_MANAGER: RefCell<MemoryManager<DefaultMemoryImpl>> = RefCell::new(MemoryManager::init(DefaultMemoryImpl::default()));
}
const MEMORY_ID_UPGRADED: MemoryId = MemoryId::new(254);
#[inline]
pub fn get_virtual_memory(memory_id: MemoryId) -> VirtualMemory {
MEMORY_MANAGER.with(|memory_manager| memory_manager.borrow().get(memory_id))
}
#[inline]
pub fn get_upgrades_memory() -> VirtualMemory {
get_virtual_memory(MEMORY_ID_UPGRADED)
}
pub fn init_cell_data<T: Storable>(memory_id: MemoryId, default: T) -> StableCell<T> {
#[allow(clippy::expect_used)] StableCell::init(get_virtual_memory(memory_id), default).expect("failed to initialize")
}
pub fn init_vec_data<T: Storable>(memory_id: MemoryId) -> StableVec<T> {
#[allow(clippy::expect_used)] StableVec::init(get_virtual_memory(memory_id)).expect("failed to initialize")
}
pub fn init_map_data<K: Storable + Ord + Clone, V: Storable>(
memory_id: MemoryId,
) -> StableBTreeMap<K, V> {
#[allow(clippy::expect_used)] StableBTreeMap::init(get_virtual_memory(memory_id))
}
pub fn init_log_data<T: Storable>(
id_memory_id: MemoryId,
data_memory_id: MemoryId,
) -> StableLog<T> {
#[allow(clippy::expect_used)] StableLog::init(
get_virtual_memory(id_memory_id),
get_virtual_memory(data_memory_id),
)
.expect("failed to initialize")
}
pub fn init_priority_queue_data<T: Storable + PartialOrd>(
memory_id: MemoryId,
) -> StablePriorityQueue<T> {
#[allow(clippy::expect_used)] StablePriorityQueue::init(get_virtual_memory(memory_id)).expect("failed to initialize")
}
pub struct WriteUpgradeMemory<'a, M> {
writer: Writer<'a, M>,
}
pub struct ReadUpgradeMemory<'a, M> {
memory: &'a M,
offset: u64,
}
impl<'a, M: Memory> WriteUpgradeMemory<'a, M> {
pub fn new(memory: &'a mut M) -> WriteUpgradeMemory<'a, M> {
Self {
writer: Writer::new(memory, 0),
}
}
pub fn write(&mut self, bytes: &[u8]) {
#[allow(clippy::expect_used)] self.writer
.write(bytes)
.expect("failed to write to upgrade memory");
}
pub fn write_u32(&mut self, value: u32) {
let mut bytes = Vec::with_capacity(4);
common::u32_to_bytes(&mut bytes, value);
self.write(&bytes);
}
pub fn write_u64(&mut self, value: u64) {
let mut bytes = Vec::with_capacity(8);
common::u64_to_bytes(&mut bytes, value);
self.write(&bytes);
}
}
impl<'a, M: Memory> ReadUpgradeMemory<'a, M> {
pub fn new(memory: &'a M) -> ReadUpgradeMemory<'a, M> {
Self { memory, offset: 0 }
}
pub fn read(&mut self, bytes: &mut [u8]) {
self.memory.read(self.offset, bytes);
self.offset += bytes.len() as u64;
}
pub fn read_u32(&mut self) -> u32 {
let mut bytes = [0; 4];
self.read(&mut bytes);
common::u32_from_bytes(&bytes)
}
pub fn read_u64(&mut self) -> u64 {
let mut bytes = [0; 8];
self.read(&mut bytes);
common::u64_from_bytes(&bytes)
}
}
pub mod common {
use super::*;
#[inline]
pub fn usize_to_4bytes(buf: &mut Vec<u8>, value: usize) {
buf.extend(&(value as u32).to_bytes()[..]);
}
#[inline]
pub fn usize_from_4bytes(bytes: &[u8]) -> usize {
u32::from_bytes(Cow::Borrowed(&bytes[..4])) as usize
}
#[inline]
pub fn u32_to_bytes(buf: &mut Vec<u8>, value: u32) {
buf.extend(&value.to_bytes()[..]);
}
#[inline]
pub fn u32_from_bytes(bytes: &[u8]) -> u32 {
u32::from_bytes(Cow::Borrowed(&bytes[..4]))
}
#[inline]
pub fn u64_to_bytes(buf: &mut Vec<u8>, value: u64) {
buf.extend(&value.to_bytes()[..]);
}
#[inline]
pub fn u64_from_bytes(bytes: &[u8]) -> u64 {
u64::from_bytes(Cow::Borrowed(&bytes[..8]))
}
}