canic_memory/runtime/
registry.rs

1use crate::registry::{
2    MemoryRange, MemoryRangeEntry, MemoryRangeSnapshot, MemoryRegistry, MemoryRegistryEntry,
3    MemoryRegistryError, drain_pending_ranges, drain_pending_registrations,
4};
5
6///
7/// MemoryRegistryInitSummary
8///
9/// Substrate-level summary of registry state after initialization.
10/// This is intended for diagnostics and testing only.
11/// It is NOT a stable API contract or external view.
12///
13
14#[derive(Debug)]
15pub struct MemoryRegistryInitSummary {
16    pub ranges: Vec<(String, MemoryRange)>,
17    pub entries: Vec<(u8, MemoryRegistryEntry)>,
18}
19
20///
21/// MemoryRegistryRuntime
22///
23/// Substrate runtime controller responsible for initializing the
24/// global memory registry.
25///
26/// This type performs mechanical coordination only:
27/// - ordering
28/// - conflict detection
29/// - idempotent initialization
30///
31/// It encodes no application semantics.
32///
33pub struct MemoryRegistryRuntime;
34
35impl MemoryRegistryRuntime {
36    /// Initialize the memory registry.
37    ///
38    /// - Optionally reserves an initial range for the caller.
39    /// - Applies all deferred range reservations.
40    /// - Applies all deferred ID registrations.
41    ///
42    /// This function is idempotent for the same initial range.
43    pub fn init(
44        initial_range: Option<(&str, u8, u8)>,
45    ) -> Result<MemoryRegistryInitSummary, MemoryRegistryError> {
46        // Reserve the caller's initial range first (if provided)
47        if let Some((crate_name, start, end)) = initial_range {
48            MemoryRegistry::reserve_range(crate_name, start, end)?;
49        }
50
51        // Apply deferred range reservations deterministically
52        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        // Apply deferred registrations deterministically
59        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    /// Snapshot all registry entries.
72    #[must_use]
73    pub fn snapshot_entries() -> Vec<(u8, MemoryRegistryEntry)> {
74        MemoryRegistry::export()
75    }
76
77    /// Snapshot all reserved memory ranges.
78    #[must_use]
79    pub fn snapshot_ranges() -> Vec<(String, MemoryRange)> {
80        MemoryRegistry::export_ranges()
81    }
82
83    /// Snapshot all reserved memory ranges with owners.
84    #[must_use]
85    pub fn snapshot_range_entries() -> Vec<MemoryRangeEntry> {
86        MemoryRegistry::export_range_entries()
87    }
88
89    /// Snapshot registry entries grouped by range.
90    #[must_use]
91    pub fn snapshot_ids_by_range() -> Vec<MemoryRangeSnapshot> {
92        MemoryRegistry::export_ids_by_range()
93    }
94
95    /// Retrieve a single registry entry by ID.
96    #[must_use]
97    pub fn get(id: u8) -> Option<MemoryRegistryEntry> {
98        MemoryRegistry::get(id)
99    }
100}
101
102///
103/// TESTS
104///
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use crate::registry::{defer_register, defer_reserve_range, reset_for_tests};
110
111    #[test]
112    fn init_applies_initial_and_pending() {
113        reset_for_tests();
114        defer_reserve_range("crate_b", 5, 6);
115        defer_register(5, "crate_b", "B5");
116
117        let summary =
118            MemoryRegistryRuntime::init(Some(("crate_a", 1, 3))).expect("init should succeed");
119
120        assert_eq!(summary.ranges.len(), 2);
121        assert_eq!(summary.entries.len(), 1);
122        assert_eq!(summary.entries[0].0, 5);
123        assert_eq!(summary.entries[0].1.label, "B5");
124    }
125
126    #[test]
127    fn init_is_idempotent_for_same_initial_range() {
128        reset_for_tests();
129
130        MemoryRegistryRuntime::init(Some(("crate_a", 1, 3))).expect("first init should succeed");
131        MemoryRegistryRuntime::init(Some(("crate_a", 1, 3))).expect("second init should succeed");
132    }
133
134    #[test]
135    fn init_returns_error_on_conflict() {
136        reset_for_tests();
137        defer_reserve_range("crate_a", 1, 3);
138        defer_reserve_range("crate_b", 3, 4);
139
140        let err = MemoryRegistryRuntime::init(None).unwrap_err();
141        assert!(matches!(err, MemoryRegistryError::Overlap { .. }));
142    }
143}