Crates.io | ic-stable-memory |
lib.rs | ic-stable-memory |
version | 0.4.4 |
source | src |
created_at | 2022-06-24 14:27:57.304404 |
updated_at | 2023-04-06 20:12:53.383137 |
description | Internet Computer's stable memory collections and tools |
homepage | |
repository | |
max_upload_size | |
id | 612424 |
size | 655,071 |
Allows using canister's stable memory as main memory.
8
stable data structures:
SBox
in replacement for Box
SVec
and SLog
in replacement for Vec
SHashMap
in replacement for HashMap
SHashSet
in replacement for HashSet
SBTreeMap
in replacement for BTreeMap
SBTreeSet
in replacement for BTreeSet
SCertifiedBTreeMap
in replacement for Dfinity's RBTree
OutOfMemory
errors, while keeping it almost identical to std
# cargo.toml
[dependencies]
ic-stable-memory = "0.4"
Let's build a Todo
app, since they're very popular :)
use candid::{CandidType, Deserialize};
use ic_cdk_macros::{init, post_upgrade, pre_upgrade, query, update};
use ic_stable_memory::collections::SVec;
use ic_stable_memory::derive::{CandidAsDynSizeBytes, StableType};
use ic_stable_memory::{
retrieve_custom_data, stable_memory_init, stable_memory_post_upgrade,
stable_memory_pre_upgrade, store_custom_data, SBox,
};
use std::cell::RefCell;
#[derive(CandidType, Deserialize, StableType, CandidAsDynSizeBytes, Debug, Clone)]
struct Task {
title: String,
description: String,
}
// If you can implement AsFixedSizeBytes for your data type,
// you can store it directly, without wrapping in SBox
type State = SVec<SBox<Task>>;
thread_local! {
static STATE: RefCell<Option<State>> = RefCell::default();
}
#[update]
fn add_task(task: Task) {
STATE.with(|s| {
let boxed_task = SBox::new(task).expect("Out of memory");
s.borrow_mut()
.as_mut()
.unwrap()
.push(boxed_task)
.expect("Out of memory");
});
}
#[update]
fn remove_task(idx: u32) {
STATE.with(|s| {
s.borrow_mut().as_mut().unwrap().remove(idx as usize);
});
}
#[update]
fn swap_tasks(idx_1: u32, idx_2: u32) {
STATE.with(|s| {
s.borrow_mut()
.as_mut()
.unwrap()
.swap(idx_1 as usize, idx_2 as usize);
});
}
#[query]
fn get_todo_list() -> Vec<Task> {
STATE.with(|s| {
let mut result = Vec::new();
for task in s.borrow().as_ref().unwrap().iter() {
result.push(task.clone());
}
result
})
}
#[init]
fn init() {
stable_memory_init();
STATE.with(|s| {
*s.borrow_mut() = Some(SVec::new());
});
}
#[pre_upgrade]
fn pre_upgrade() {
let state: State = STATE.with(|s| s.borrow_mut().take().unwrap());
let boxed_state = SBox::new(state).expect("Out of memory");
store_custom_data(0, boxed_state);
stable_memory_pre_upgrade().expect("Out of memory");
}
#[post_upgrade]
fn post_upgrade() {
stable_memory_post_upgrade();
let state = retrieve_custom_data::<State>(0).unwrap().into_inner();
STATE.with(|s| {
*s.borrow_mut() = Some(state);
});
}
OutOfMemory
errorsic-stable-memory
follows semantic versioning guidelines and takes them one step further. You're safe to update this
dependency when minor or patch version changes. But if the major version changes, it means that your canister won't be
able to work with the new version and you shouldn't update. Such an event won't happen often and, in fact, this library
has a lot of room to improve without breaking changes, but this may happen.
This is an emerging software, so any help is greatly appreciated. Feel free to propose PR's, architecture tips, bug reports or any other feedback via Github issues.
cargo install grcov
rustup component add llvm-tools-preview
./coverage.sh --test
(won't rebuild without --test
)