canic-memory
Shared stable-memory utilities extracted from the Canic toolkit. This crate can be used on its own by any IC canister crate (including non-Canic projects) to:
- manage stable-memory segments via a shared
MemoryManager - declare and validate per-crate memory ID ranges
- register stable structures declaratively with macros
- force eager initialization of thread-local statics that allocate memory
It depends only on canic-core (for bounded types/storable macros) and canic-cdk (for the IC stable-structures glue). There is no dependency on the canic crate.
Modules
manager— thread-localMemoryManager<DefaultMemoryImpl>used by all helpers.registry— range reservation + ID registry with pending queues for macro-driven registration.ops— helper to flush pending reservations/registrations into the registry during startup.runtime— eager TLS initialization helper.macros—ic_memory!,ic_memory_range!,eager_static!,eager_init!.
Quick start
Add the crate to your Cargo.toml:
= { = true }
Reserve a range and declare a memory slot
// Reserve IDs 10–19 for this crate (usually in a module's init or ctor).
ic_memory_range!;
// Declare a stable-memory slot at ID 10 and wrap it in a stable BTreeMap.
use ic_memory;
use ;
use RefCell;
thread_local!
Flush pending registrations during startup
Call the ops helper once during your init/post-upgrade flow to validate ranges and IDs and apply any pending registrations queued by macros:
use MemoryRegistryOps;
init_memory will:
- reserve the optional initial range,
- apply all pending range reservations,
- apply all pending ID registrations (sorted),
- return a summary of ranges/entries for logging or inspection.
Eagerly initialize thread-locals that allocate memory
When you wrap stable structures in thread_local!, make sure they initialize deterministically before your canister entrypoints execute:
use ;
use RefCell;
eager_static!
eager_init!;
Error handling
The registry surfaces MemoryRegistryError for:
- duplicate ranges, overlapping ranges, invalid range (start > end)
- registration outside the crate's reserved ranges
- conflicting registrations on an ID with a different label
- missing range for the crate
Handle these at init time so your canister fails fast on invalid memory layout.
Testing helpers
registry::reset_for_tests() clears the registry and pending queues to keep unit tests isolated. Example:
Notes
- The macros automatically namespace memory IDs by crate (
CARGO_PKG_NAME) when validating ranges. - If you don't want an initial range, omit it and rely solely on
ic_memory_range!calls beforeinit_memory. - Consumers outside Canic can import only
canic-memoryandcanic-core/canic-cdk; the rest of the stack is optional.