canic_memory/runtime/
registry.rs1use crate::registry::{
2 MemoryRange, MemoryRegistry, MemoryRegistryEntry, MemoryRegistryError, drain_pending_ranges,
3 drain_pending_registrations,
4};
5
6#[derive(Debug)]
15pub struct MemoryRegistryInitSummary {
16 pub ranges: Vec<(String, MemoryRange)>,
17 pub entries: Vec<(u8, MemoryRegistryEntry)>,
18}
19
20pub struct MemoryRegistryRuntime;
34
35impl MemoryRegistryRuntime {
36 pub fn init(
44 initial_range: Option<(&str, u8, u8)>,
45 ) -> Result<MemoryRegistryInitSummary, MemoryRegistryError> {
46 if let Some((crate_name, start, end)) = initial_range {
48 MemoryRegistry::reserve_range(crate_name, start, end)?;
49 }
50
51 let mut ranges = drain_pending_ranges();
53 ranges.sort_by_key(|(_, start, _)| *start);
54 for (crate_name, start, end) in ranges {
55 MemoryRegistry::reserve_range(&crate_name, start, end)?;
56 }
57
58 let mut regs = drain_pending_registrations();
60 regs.sort_by_key(|(id, _, _)| *id);
61 for (id, crate_name, label) in regs {
62 MemoryRegistry::register(id, &crate_name, &label)?;
63 }
64
65 Ok(MemoryRegistryInitSummary {
66 ranges: MemoryRegistry::export_ranges(),
67 entries: MemoryRegistry::export(),
68 })
69 }
70
71 #[must_use]
73 pub fn snapshot_entries() -> Vec<(u8, MemoryRegistryEntry)> {
74 MemoryRegistry::export()
75 }
76
77 #[must_use]
79 pub fn snapshot_ranges() -> Vec<(String, MemoryRange)> {
80 MemoryRegistry::export_ranges()
81 }
82
83 #[must_use]
85 pub fn get(id: u8) -> Option<MemoryRegistryEntry> {
86 MemoryRegistry::get(id)
87 }
88}
89
90#[cfg(test)]
95mod tests {
96 use super::*;
97 use crate::registry::{defer_register, defer_reserve_range, reset_for_tests};
98
99 #[test]
100 fn init_applies_initial_and_pending() {
101 reset_for_tests();
102 defer_reserve_range("crate_b", 5, 6);
103 defer_register(5, "crate_b", "B5");
104
105 let summary =
106 MemoryRegistryRuntime::init(Some(("crate_a", 1, 3))).expect("init should succeed");
107
108 assert_eq!(summary.ranges.len(), 2);
109 assert_eq!(summary.entries.len(), 1);
110 assert_eq!(summary.entries[0].0, 5);
111 assert_eq!(summary.entries[0].1.label, "B5");
112 }
113
114 #[test]
115 fn init_is_idempotent_for_same_initial_range() {
116 reset_for_tests();
117
118 MemoryRegistryRuntime::init(Some(("crate_a", 1, 3))).expect("first init should succeed");
119 MemoryRegistryRuntime::init(Some(("crate_a", 1, 3))).expect("second init should succeed");
120 }
121
122 #[test]
123 fn init_returns_error_on_conflict() {
124 reset_for_tests();
125 defer_reserve_range("crate_a", 1, 3);
126 defer_reserve_range("crate_b", 3, 4);
127
128 let err = MemoryRegistryRuntime::init(None).unwrap_err();
129 assert!(matches!(err, MemoryRegistryError::Overlap { .. }));
130 }
131}