From 901fddace7c8a710ba7e0eeace13e477f83b6dde Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Mon, 28 Apr 2025 18:09:32 +0300 Subject: [PATCH 01/14] docs: add memory trait and memory manger documentation to book --- docs/src/SUMMARY.md | 4 +++ docs/src/concepts.md | 3 ++ docs/src/memory-manager.md | 37 +++++++++++++++++++ docs/src/memory-trait.md | 74 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 docs/src/concepts.md create mode 100644 docs/src/memory-manager.md create mode 100644 docs/src/memory-trait.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index b5e0bd95..d1a979a4 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -4,4 +4,8 @@ - [Design Principles](./design-principles.md) - [Available Data Structures](./available-data-structures.md) +- [Concepts](./concepts.md) + - [The Memory Trait](./memory-trait.md) + - [Memory Manager](./memory-manager.md) + - [Schema Upgrades](./schema-upgrades.md) diff --git a/docs/src/concepts.md b/docs/src/concepts.md new file mode 100644 index 00000000..e82843cb --- /dev/null +++ b/docs/src/concepts.md @@ -0,0 +1,3 @@ +# Concepts + +This section covers fundamental concepts for understanding how stable structures work and how they can be used effectively. diff --git a/docs/src/memory-manager.md b/docs/src/memory-manager.md new file mode 100644 index 00000000..cccb3ccd --- /dev/null +++ b/docs/src/memory-manager.md @@ -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 data structure and its associated memory, not other 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 + +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 = BTreeMap::init(mem_mgr.get(MemoryId::new(0))); +let mut map_2: BTreeMap = 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. +``` diff --git a/docs/src/memory-trait.md b/docs/src/memory-trait.md new file mode 100644 index 00000000..78f494f1 --- /dev/null +++ b/docs/src/memory-trait.md @@ -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` +- `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 = 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 = BTreeMap::init(DefaultMemoryImpl::default()); +let mut map_2: BTreeMap = 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. From 6cf6dd4292fd3d38d26de07874d915be78a2d5c9 Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Mon, 28 Apr 2025 18:17:06 +0300 Subject: [PATCH 02/14] . --- docs/book.toml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/book.toml diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 00000000..6d59056e --- /dev/null +++ b/docs/book.toml @@ -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` From 8b2742c435c3dd00c6f432fa4ea400adb5e34b05 Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 29 Apr 2025 09:16:09 +0300 Subject: [PATCH 03/14] Deploy mdbook --- .github/workflows/ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afd4f2c6..17f5f090 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,6 +130,25 @@ jobs: run: | bash ./scripts/ci_post_run_benchmark.sh + documentation-book: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup mdBook + uses: peaceiris/actions-mdbook@v2 + with: + mdbook-version: '0.4.48' + + - run: mdbook build + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.ref == 'refs/heads/main' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/book + checks-pass: # Always run this job! if: always() From e03d2e745027e5d434acc1f5536e436db1981f68 Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 29 Apr 2025 09:24:05 +0300 Subject: [PATCH 04/14] . --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17f5f090..c2614c1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,7 +140,7 @@ jobs: with: mdbook-version: '0.4.48' - - run: mdbook build + - run: mdbook build ./docs - name: Deploy uses: peaceiris/actions-gh-pages@v3 From dd3c4093b90ddbcc37b13957030d8cf818ebd3f7 Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 29 Apr 2025 09:27:59 +0300 Subject: [PATCH 05/14] . --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2614c1b..57352785 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,9 +136,13 @@ jobs: - uses: actions/checkout@v4 - name: Setup mdBook - uses: peaceiris/actions-mdbook@v2 + uses: jontze/action-mdbook@v3 with: - mdbook-version: '0.4.48' + token: ${{secrets.GITHUB_TOKEN}} + mdbook-version: "0.4.48" + use-linkcheck: true + use-admonish: true + admonish-version: "1.19.0" - run: mdbook build ./docs From 135fcd2410296488764446ffb258eb86cd10b85f Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 29 Apr 2025 09:29:50 +0300 Subject: [PATCH 06/14] . --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57352785..b8fdc0d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -142,7 +142,6 @@ jobs: mdbook-version: "0.4.48" use-linkcheck: true use-admonish: true - admonish-version: "1.19.0" - run: mdbook build ./docs From 2e5fe650104d87278454c09ed0dc58690792d297 Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 29 Apr 2025 09:32:09 +0300 Subject: [PATCH 07/14] . --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8fdc0d7..9bd0ca57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,7 +140,6 @@ jobs: with: token: ${{secrets.GITHUB_TOKEN}} mdbook-version: "0.4.48" - use-linkcheck: true use-admonish: true - run: mdbook build ./docs From 223718874ef51889e37633019f422efd835b8b2b Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 29 Apr 2025 09:37:59 +0300 Subject: [PATCH 08/14] . --- docs/mdbook-admonish.css | 351 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 docs/mdbook-admonish.css diff --git a/docs/mdbook-admonish.css b/docs/mdbook-admonish.css new file mode 100644 index 00000000..88dd2b15 --- /dev/null +++ b/docs/mdbook-admonish.css @@ -0,0 +1,351 @@ +@charset "UTF-8"; +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} +a.admonition-anchor-link::before { + content: "§"; +} + +:is(.admonition-title, summary.admonition-title) { + position: relative; + min-height: 4rem; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + print-color-adjust: exact; + -webkit-print-color-adjust: exact; + display: flex; +} +:is(.admonition-title, summary.admonition-title) p { + margin: 0; +} +html :is(.admonition-title, summary.admonition-title):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary.admonition-title)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + print-color-adjust: exact; + -webkit-print-color-adjust: exact; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} +:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} +summary.admonition-title::-webkit-details-marker { + display: none; +} + +:root { + --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); +} + +:root { + --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition):is(.admonish-note) { + border-color: #448aff; +} + +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--admonish-note); + -webkit-mask-image: var(--md-admonition-icon--admonish-note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { + border-color: #00b0ff; +} + +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--admonish-abstract); + -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-info, .admonish-todo) { + border-color: #00b8d4; +} + +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--admonish-info); + -webkit-mask-image: var(--md-admonition-icon--admonish-info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { + border-color: #00bfa5; +} + +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--admonish-tip); + -webkit-mask-image: var(--md-admonition-icon--admonish-tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { + border-color: #00c853; +} + +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--admonish-success); + -webkit-mask-image: var(--md-admonition-icon--admonish-success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { + border-color: #64dd17; +} + +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--admonish-question); + -webkit-mask-image: var(--md-admonition-icon--admonish-question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { + border-color: #ff9100; +} + +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--admonish-warning); + -webkit-mask-image: var(--md-admonition-icon--admonish-warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { + border-color: #ff5252; +} + +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--admonish-failure); + -webkit-mask-image: var(--md-admonition-icon--admonish-failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-danger, .admonish-error) { + border-color: #ff1744; +} + +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--admonish-danger); + -webkit-mask-image: var(--md-admonition-icon--admonish-danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-bug) { + border-color: #f50057; +} + +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--admonish-bug); + -webkit-mask-image: var(--md-admonition-icon--admonish-bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-example) { + border-color: #7c4dff; +} + +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--admonish-example); + -webkit-mask-image: var(--md-admonition-icon--admonish-example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-quote, .admonish-cite) { + border-color: #9e9e9e; +} + +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--admonish-quote); + -webkit-mask-image: var(--md-admonition-icon--admonish-quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), +.coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} From 5f384b5e5df960204a575d3c14930b1a3a5dce1f Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 6 May 2025 10:31:10 +0200 Subject: [PATCH 09/14] . --- .github/workflows/ci.yml | 5 +- docs/.gitignore | 2 + docs/book.toml | 1 + docs/mdbook-admonish.css | 351 --------------------------------------- 4 files changed, 7 insertions(+), 352 deletions(-) create mode 100644 docs/.gitignore delete mode 100644 docs/mdbook-admonish.css diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bd0ca57..55d4b182 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,7 +154,7 @@ jobs: checks-pass: # Always run this job! if: always() - needs: [build, examples, benchmark] + needs: [build, examples, benchmark, documentation-book] runs-on: ubuntu-latest steps: - name: check build result @@ -166,3 +166,6 @@ jobs: - name: check benchmark result if: ${{ needs.benchmark.result != 'success' }} run: exit 1 + - name: check documentation-book result + if: ${{ needs.documentation-book.result != 'success' }} + run: exit 1 diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..57030c42 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +*.css +book diff --git a/docs/book.toml b/docs/book.toml index 6d59056e..a4801568 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -18,3 +18,4 @@ additional-css = ["./mdbook-admonish.css"] [preprocessor.admonish] command = "mdbook-admonish" assets_version = "3.0.3" # do not edit: managed by `mdbook-admonish install` + diff --git a/docs/mdbook-admonish.css b/docs/mdbook-admonish.css deleted file mode 100644 index 88dd2b15..00000000 --- a/docs/mdbook-admonish.css +++ /dev/null @@ -1,351 +0,0 @@ -@charset "UTF-8"; -:is(.admonition) { - display: flow-root; - margin: 1.5625em 0; - padding: 0 1.2rem; - color: var(--fg); - page-break-inside: avoid; - background-color: var(--bg); - border: 0 solid black; - border-inline-start-width: 0.4rem; - border-radius: 0.2rem; - box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); -} -@media print { - :is(.admonition) { - box-shadow: none; - } -} -:is(.admonition) > * { - box-sizing: border-box; -} -:is(.admonition) :is(.admonition) { - margin-top: 1em; - margin-bottom: 1em; -} -:is(.admonition) > .tabbed-set:only-child { - margin-top: 0; -} -html :is(.admonition) > :last-child { - margin-bottom: 1.2rem; -} - -a.admonition-anchor-link { - display: none; - position: absolute; - left: -1.2rem; - padding-right: 1rem; -} -a.admonition-anchor-link:link, a.admonition-anchor-link:visited { - color: var(--fg); -} -a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { - text-decoration: none; -} -a.admonition-anchor-link::before { - content: "§"; -} - -:is(.admonition-title, summary.admonition-title) { - position: relative; - min-height: 4rem; - margin-block: 0; - margin-inline: -1.6rem -1.2rem; - padding-block: 0.8rem; - padding-inline: 4.4rem 1.2rem; - font-weight: 700; - background-color: rgba(68, 138, 255, 0.1); - print-color-adjust: exact; - -webkit-print-color-adjust: exact; - display: flex; -} -:is(.admonition-title, summary.admonition-title) p { - margin: 0; -} -html :is(.admonition-title, summary.admonition-title):last-child { - margin-bottom: 0; -} -:is(.admonition-title, summary.admonition-title)::before { - position: absolute; - top: 0.625em; - inset-inline-start: 1.6rem; - width: 2rem; - height: 2rem; - background-color: #448aff; - print-color-adjust: exact; - -webkit-print-color-adjust: exact; - mask-image: url('data:image/svg+xml;charset=utf-8,'); - -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ""; -} -:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { - display: initial; -} - -details.admonition > summary.admonition-title::after { - position: absolute; - top: 0.625em; - inset-inline-end: 1.6rem; - height: 2rem; - width: 2rem; - background-color: currentcolor; - mask-image: var(--md-details-icon); - -webkit-mask-image: var(--md-details-icon); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ""; - transform: rotate(0deg); - transition: transform 0.25s; -} -details[open].admonition > summary.admonition-title::after { - transform: rotate(90deg); -} -summary.admonition-title::-webkit-details-marker { - display: none; -} - -:root { - --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); -} - -:root { - --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); -} - -:is(.admonition):is(.admonish-note) { - border-color: #448aff; -} - -:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(68, 138, 255, 0.1); -} -:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #448aff; - mask-image: var(--md-admonition-icon--admonish-note); - -webkit-mask-image: var(--md-admonition-icon--admonish-note); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { - border-color: #00b0ff; -} - -:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 176, 255, 0.1); -} -:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00b0ff; - mask-image: var(--md-admonition-icon--admonish-abstract); - -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-info, .admonish-todo) { - border-color: #00b8d4; -} - -:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 184, 212, 0.1); -} -:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00b8d4; - mask-image: var(--md-admonition-icon--admonish-info); - -webkit-mask-image: var(--md-admonition-icon--admonish-info); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { - border-color: #00bfa5; -} - -:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 191, 165, 0.1); -} -:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00bfa5; - mask-image: var(--md-admonition-icon--admonish-tip); - -webkit-mask-image: var(--md-admonition-icon--admonish-tip); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { - border-color: #00c853; -} - -:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 200, 83, 0.1); -} -:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00c853; - mask-image: var(--md-admonition-icon--admonish-success); - -webkit-mask-image: var(--md-admonition-icon--admonish-success); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { - border-color: #64dd17; -} - -:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(100, 221, 23, 0.1); -} -:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #64dd17; - mask-image: var(--md-admonition-icon--admonish-question); - -webkit-mask-image: var(--md-admonition-icon--admonish-question); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { - border-color: #ff9100; -} - -:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(255, 145, 0, 0.1); -} -:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #ff9100; - mask-image: var(--md-admonition-icon--admonish-warning); - -webkit-mask-image: var(--md-admonition-icon--admonish-warning); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { - border-color: #ff5252; -} - -:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(255, 82, 82, 0.1); -} -:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #ff5252; - mask-image: var(--md-admonition-icon--admonish-failure); - -webkit-mask-image: var(--md-admonition-icon--admonish-failure); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-danger, .admonish-error) { - border-color: #ff1744; -} - -:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(255, 23, 68, 0.1); -} -:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #ff1744; - mask-image: var(--md-admonition-icon--admonish-danger); - -webkit-mask-image: var(--md-admonition-icon--admonish-danger); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-bug) { - border-color: #f50057; -} - -:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(245, 0, 87, 0.1); -} -:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #f50057; - mask-image: var(--md-admonition-icon--admonish-bug); - -webkit-mask-image: var(--md-admonition-icon--admonish-bug); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-example) { - border-color: #7c4dff; -} - -:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(124, 77, 255, 0.1); -} -:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #7c4dff; - mask-image: var(--md-admonition-icon--admonish-example); - -webkit-mask-image: var(--md-admonition-icon--admonish-example); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-quote, .admonish-cite) { - border-color: #9e9e9e; -} - -:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(158, 158, 158, 0.1); -} -:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #9e9e9e; - mask-image: var(--md-admonition-icon--admonish-quote); - -webkit-mask-image: var(--md-admonition-icon--admonish-quote); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -.navy :is(.admonition) { - background-color: var(--sidebar-bg); -} - -.ayu :is(.admonition), -.coal :is(.admonition) { - background-color: var(--theme-hover); -} - -.rust :is(.admonition) { - background-color: var(--sidebar-bg); - color: var(--sidebar-fg); -} -.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { - color: var(--sidebar-fg); -} From 484c5931418fdfbcefefd5888e470b1e2f4f370d Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 6 May 2025 10:42:11 +0200 Subject: [PATCH 10/14] . --- .github/workflows/ci.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55d4b182..6f7197c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,12 +135,16 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup mdBook - uses: jontze/action-mdbook@v3 - with: - token: ${{secrets.GITHUB_TOKEN}} - mdbook-version: "0.4.48" - use-admonish: true + - name: Install Rust + run: | + rustup update ${{ matrix.rust }} --no-self-update + rustup default ${{ matrix.rust }} + rustup target add wasm32-unknown-unknown + + - name: Install mdbook + run: | + cargo install mdbook --version 0.4.48 + cargo install mdbook-admonish --version 1.19.0 - run: mdbook build ./docs From 226b577069d1d0d40df256b5a18a10851f2b4398 Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 6 May 2025 10:47:30 +0200 Subject: [PATCH 11/14] . --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f7197c4..7ac47677 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,7 +146,10 @@ jobs: cargo install mdbook --version 0.4.48 cargo install mdbook-admonish --version 1.19.0 - - run: mdbook build ./docs + - name: Build book + run: | + mdbook-admonish install ./docs + mdbook build ./docs - name: Deploy uses: peaceiris/actions-gh-pages@v3 From 0687ac0f086233edbd31be9e6a048592890fe49d Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 6 May 2025 10:52:10 +0200 Subject: [PATCH 12/14] . --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ac47677..3bad5a9a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,8 +148,8 @@ jobs: - name: Build book run: | - mdbook-admonish install ./docs - mdbook build ./docs + mdbook-admonish install ./docs + mdbook build ./docs - name: Deploy uses: peaceiris/actions-gh-pages@v3 From b029d95fad52c30da66c70c84b031f66efcf40ed Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 6 May 2025 11:05:08 +0200 Subject: [PATCH 13/14] . --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3bad5a9a..363e8b7d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,8 +148,9 @@ jobs: - name: Build book run: | - mdbook-admonish install ./docs - mdbook build ./docs + cd docs + mdbook-admonish install + mdbook build - name: Deploy uses: peaceiris/actions-gh-pages@v3 From c31f57f657f881a1d7740b3d5d4ae872a816c0fe Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Tue, 6 May 2025 11:14:16 +0200 Subject: [PATCH 14/14] . --- docs/src/SUMMARY.md | 4 --- docs/src/concepts.md | 3 -- docs/src/memory-manager.md | 37 ------------------- docs/src/memory-trait.md | 74 -------------------------------------- 4 files changed, 118 deletions(-) delete mode 100644 docs/src/concepts.md delete mode 100644 docs/src/memory-manager.md delete mode 100644 docs/src/memory-trait.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index f47679f2..ecc463c0 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -8,8 +8,4 @@ - [The Memory Trait](./concepts/memory-trait.md) - [Memory Manager](./concepts/memory-manager.md) -- [Concepts](./concepts.md) - - [The Memory Trait](./memory-trait.md) - - [Memory Manager](./memory-manager.md) - - [Schema Upgrades](./schema-upgrades.md) diff --git a/docs/src/concepts.md b/docs/src/concepts.md deleted file mode 100644 index e82843cb..00000000 --- a/docs/src/concepts.md +++ /dev/null @@ -1,3 +0,0 @@ -# Concepts - -This section covers fundamental concepts for understanding how stable structures work and how they can be used effectively. diff --git a/docs/src/memory-manager.md b/docs/src/memory-manager.md deleted file mode 100644 index cccb3ccd..00000000 --- a/docs/src/memory-manager.md +++ /dev/null @@ -1,37 +0,0 @@ -# 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 data structure and its associated memory, not other 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 - -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 = BTreeMap::init(mem_mgr.get(MemoryId::new(0))); -let mut map_2: BTreeMap = 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. -``` diff --git a/docs/src/memory-trait.md b/docs/src/memory-trait.md deleted file mode 100644 index 78f494f1..00000000 --- a/docs/src/memory-trait.md +++ /dev/null @@ -1,74 +0,0 @@ -# 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` -- `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 = 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 = BTreeMap::init(DefaultMemoryImpl::default()); -let mut map_2: BTreeMap = 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.