canic-memory
canic-memory provides stable-memory helpers for Internet Computer canisters. It
can be used on its own, without the rest of Canic, when a crate needs one shared
memory manager, deterministic thread-local initialization, and validation for
stable-memory ID ownership.
The crate currently declares MSRV 1.91.0. The Canic workspace may build with a
newer pinned toolchain, but downstream crates compiling canic-memory from
source should only need Rust 1.91.0 or newer.
What It Provides
- A shared
MemoryManager<DefaultMemoryImpl>used by all helpers. - Per-crate memory ID range reservation and overlap validation.
ic_memory!andic_memory_range!for declarative stable-memory slots.MemoryApifor runtime-selected stable-memory IDs.eager_static!andeager_init!for deterministic startup initialization.impl_storable_bounded!andimpl_storable_unbounded!for CBOR-backedStorableimplementations.- A
canic_cdkre-export atcanic_memory::cdk.
Install
Inside the Canic workspace, use the workspace dependency:
= { = true }
From another crate, depend on the published crate:
= "0.29"
Quick Start
Declare stable structures with eager_static! so they are touched during
startup, not lazily during the first endpoint call.
use ;
use ;
use RefCell;
;
eager_static!
Bootstrap memory during canister startup before any endpoint uses the stable structures:
use MemoryApi;
bootstrap_owner_range(...) performs the standalone startup sequence:
- Touch every
eager_static!thread-local. - Run every registered
eager_init!body. - Reserve the caller's owner range.
- Flush pending
ic_memory_range!andic_memory!registrations.
When using the full Canic facade (canic::start! or canic::start_root!), Canic
runs this lifecycle wiring for you.
Memory Ranges
Stable-memory IDs are global inside one canister. Reserve a range for each crate that owns stable structures, then keep that crate's IDs inside the range.
use ;
eager_init!;
Range validation catches:
- overlapping ranges
start > end- duplicate IDs
- IDs outside the owner's reserved range
- IDs owned by another crate
- ID
255, which is reserved for stable-structures internals
Exact duplicate range reservations for the same crate are allowed so init and post-upgrade can share the same bootstrap path.
Runtime-Selected Slots
Use MemoryApi when the memory ID is chosen dynamically and ic_memory! is not
a good fit.
use MemoryApi;
MemoryApi::register(...) is idempotent for the same owner and label, but it
returns MemoryRegistryError::DuplicateId if the same ID is reused for a
different registration.
Registry Introspection
Use the supported MemoryApi reads for validation, diagnostics, or endpoint
responses:
use MemoryApi;
Lower-level registry snapshot helpers also exist for debugging and tests:
MemoryRegistry::export_range_entries()MemoryRegistry::export_ids_by_range()
Prefer MemoryApi for normal supported reads.
Storable Helpers
The storable macros implement ic-stable-structures Storable with Canic's
shared CBOR serializer.
use impl_storable_bounded;
use ;
impl_storable_bounded!;
Use impl_storable_bounded!(Type, max_size, is_fixed_size) when the serialized
size has a known bound. Use impl_storable_unbounded!(Type) only for data that
is expected to grow beyond a practical fixed bound.
Standalone Lifecycle
For standalone canisters, call one of the bootstrap helpers from init and post-upgrade before handling user calls:
use MemoryApi;
If all owner ranges are already queued through ic_memory_range!, and the
caller does not need to reserve an additional initial range, use:
use MemoryApi;
Accessing an ic_memory! slot on wasm32 before bootstrap will panic with a
message pointing back to memory bootstrap. This is intentional: stable memory
layout problems should fail during lifecycle startup, not during a user call.
Testing
Unit tests that touch the registry can reset global state with
registry::reset_for_tests():
reset_for_tests() is only available under cfg(test).
Module Map
api- supported runtime API for bootstrapping, registration, and reads.manager- shared thread-local memory manager.registry- range reservation, ID registration, pending queues, and errors.runtime- eager TLS execution and registry startup glue.macros- exported memory, runtime, and storable macros.serialize- CBOR serialization helpers used by storable macros.
Notes
- Memory IDs are
u8values. Application code may use0..=254;255is reserved internally. ic_memory!labels are type paths. Define a small marker type, such asstruct Users;, for each slot.- Consumers outside Canic can import only
canic-memorypluscanic-cdk; the rest of the Canic stack is optional.