3 个版本
0.4.2 | 2023年2月22日 |
---|---|
0.4.1 | 2023年1月29日 |
0.4.0 | 2023年1月29日 |
#41 in #collections
每月下载量 770
用于 ic-stable-memory
19KB
395 行
IC 稳定内存
允许将 canister 的稳定内存用作主内存。
功能
8
稳定数据结构SBox
用于替代Box
SVec
和SLog
用于替代Vec
SHashMap
用于替代HashMap
SHashSet
用于替代HashSet
SBTreeMap
用于替代BTreeMap
SBTreeSet
用于替代BTreeSet
SCertifiedBTreeMap
用于替代 Dfinity 的RBTree
SCertifiedBTreeSet
作为SCertifiedBTreeMap<T, ()>
的轻量级包装
- 强制执行 Rust 的借用规则
- 数据结构在离开作用域时自动释放
- 数据结构拥有其内部值,允许通过引用访问
- API 允许程序对
OutOfMemory
错误进行编程式响应,同时几乎与std
相同 - 构建您自己的稳定数据结构的完整工具集
安装
# cargo.toml
[dependencies]
ic-stable-memory = "0.4"
快速示例
让我们构建一个 Todo
应用程序,因为它们非常受欢迎 :)
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);
});
}
文档
- 快速入门
- 完整的 API 文档
- 如何迁移运行中的 canister
- 如何处理
OutOfMemory
错误 - 如何确保数据可升级性
- 如何实现编码特性
- 如何节省 cycles 并使其更快
- 基准测试
- 如何构建您自己的稳定数据结构
- 内部结构
示例项目
版本控制
ic-stable-memory
遵循语义版本控制指南,并将其推进了一步。当小版本或补丁版本发生变化时,您可以安全地更新这个依赖项。但如果主要版本发生变化,这意味着您的canister将无法与新版本兼容,因此不应更新。这种事件不会经常发生,实际上,这个库有很多改进的空间,而无需破坏性更改,但这可能发生。
贡献
这是一个新兴的软件,因此任何帮助都备受赞赏。您可以通过Github issues自由提出PR、架构建议、错误报告或任何其他反馈。
测试覆盖率检查
cargo安装 grcov
rustup组件添加 llvm-tools-preview
./coverage.sh --test
(没有--test
将不会重新构建)
依赖项
~1.5MB
~34K SLoC