Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[book]
title = "Stable Structures"
description = "Documentation for the Stable Structures library"
authors = ["DFINITY Foundation"]
language = "en"
multilingual = false

[build]
build-dir = "book"
create-missing = false

[output.html]
git-repository-url = "https://github.com/dfinity/stable-structures"
additional-css = ["./mdbook-admonish.css"]

[preprocessor]

[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "3.0.3" # do not edit: managed by `mdbook-admonish install`
10 changes: 7 additions & 3 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Summary

- [Introduction](./introduction.md)
- [Design Principles](./design-principles.md)
- [Available Data Structures](./available-data-structures.md)
- [Introduction](./introduction/introduction.md)
- [Design Principles](./introduction/design-principles.md)
- [Available Data Structures](./introduction/available-data-structures.md)

- [Concepts](./concepts/concepts.md)
- [The Memory Trait](./concepts/memory-trait.md)
- [Memory Manager](./concepts/memory-manager.md)

- [Schema Upgrades](./schema-upgrades.md)
3 changes: 3 additions & 0 deletions docs/src/concepts/concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Concepts

This section covers fundamental concepts for understanding how stable structures work and how they can be used effectively and safely.
37 changes: 37 additions & 0 deletions docs/src/concepts/memory-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Memory Manager

As mentioned in the previous section, each stable structure requires its own dedicated `Memory` instance.
This is an intentional design decision that limits [the blast radius](./design-principles.md) of potential bugs, ensuring that issues only affect the specific stable structure and its associated memory, not other stable structures.

## Overview

The Memory Manager enables the creation of up to 255 virtual memories from a single underlying memory instance.
When used with stable memory, this allows you to maintain up to 255 separate stable structures, each with its own isolated memory space.

## Usage Example

The following example demonstrates how to use the Memory Manager to create multiple stable structures:

```rust
use ic_stable_structures::{
memory_manager::{MemoryId, MemoryManager},
BTreeMap, DefaultMemoryImpl,
};

// Initialize a MemoryManager with DefaultMemoryImpl as the underlying memory
let mem_mgr = MemoryManager::init(DefaultMemoryImpl::default());

// Create two separate BTreeMaps, each with its own virtual memory
let mut map_1: BTreeMap<u64, u64, _> = BTreeMap::init(mem_mgr.get(MemoryId::new(0)));
let mut map_2: BTreeMap<u64, u64, _> = BTreeMap::init(mem_mgr.get(MemoryId::new(1)));

// Demonstrate independent operation of the two maps
map_1.insert(1, 2);
map_2.insert(1, 3);
assert_eq!(map_1.get(&1), Some(2)); // Succeeds as expected
```

```admonish warning ""
Virtual memories from the `MemoryManager` cannot be shared between stable structures.
Each memory instance should be assigned to exactly one stable structure.
```
74 changes: 74 additions & 0 deletions docs/src/concepts/memory-trait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# The Memory Trait

Stable structures are responsible for managing their own memory.
To provide maximum flexibility, the library introduces the `Memory` trait:

```rust
pub trait Memory {
/// Equivalent to WebAssembly memory.size.
fn size(&self) -> u64;

/// Equivalent to WebAssembly memory.grow.
fn grow(&self, pages: u64) -> i64;

/// Copies bytes from this memory to the heap (in Wasm, memory 0).
fn read(&self, offset: u64, dst: &mut [u8]);

/// Writes bytes from the heap (in Wasm, memory 0) to this memory.
fn write(&self, offset: u64, src: &[u8]);
}
```

The `Memory` trait intentionally models a [WebAssembly memory instance](https://webassembly.github.io/multi-memory/core/exec/runtime.html#memory-instances).
This design choice ensures consistency with the interface of memories available to canisters.
It also provides future compatibility with potential multi-memory support in canisters.

## Available Memory Implementations

The library provides several implementations of the `Memory` trait, each designed for specific use cases:

- `Ic0StableMemory`: Stores data in the Internet Computer's stable memory
- `VectorMemory`: An in-memory implementation backed by a Rust `Vec<u8>`
- `DefaultMemoryImpl`: A smart implementation that automatically selects the appropriate memory backend:
- Uses `Ic0StableMemory` when running in an Internet Computer canister (wasm32 target)
- Falls back to `VectorMemory` in other environments (like tests or non-IC contexts)

Additional implementations such as `FileMemory` and `RestrictedMemory` exist but are less commonly used.

```admonish note ""
In most cases, you should use `DefaultMemoryImpl` as your memory implementation.
```

### Usage Example

Here's how to initialize a stable `BTreeMap` using `DefaultMemoryImpl`:

```rust
use ic_stable_structures::{BTreeMap, DefaultMemoryImpl};
let mut map: BTreeMap<u64, u64, _> = BTreeMap::init(DefaultMemoryImpl::default());
```

```admonish warning ""
**Important**: Stable structures cannot share memories.
Each memory must be dedicated to a single stable structure.
```

While the above example works correctly, it demonstrates a potential issue: the `BTreeMap` will use the entire stable memory.
This becomes problematic when trying to use multiple stable structures.
For example, the following code will fail in a canister:

```rust
use ic_stable_structures::{BTreeMap, DefaultMemoryImpl};
let mut map_1: BTreeMap<u64, u64, _> = BTreeMap::init(DefaultMemoryImpl::default());
let mut map_2: BTreeMap<u64, u64, _> = BTreeMap::init(DefaultMemoryImpl::default());

map_1.insert(1, 2);
map_2.insert(1, 3);
assert_eq!(map_1.get(&1), Some(2)); // This assertion fails.
```

The code fails because both `map_1` and `map_2` are using the same stable memory.
This causes changes in one map to affect or corrupt the other.

To solve this problem, the library provides the [MemoryManager](./memory-manager.md), which creates up to 255 virtual memories from a single memory instance.
We'll explore this solution in the next section.
File renamed without changes.