canic_memory/
ops.rs

1use crate::registry::{
2    MemoryRange, MemoryRegistry, MemoryRegistryEntry, MemoryRegistryError, MemoryRegistryView,
3    drain_pending_ranges, drain_pending_registrations,
4};
5
6///
7/// MemoryRegistrySummary
8/// Summary of memory registry state after initialization.
9///
10
11#[derive(Debug)]
12pub struct MemoryRegistrySummary {
13    pub ranges: Vec<(String, MemoryRange)>,
14    pub entries: MemoryRegistryView,
15}
16
17///
18/// MemoryRegistryOps
19/// Ops wrapper around the global memory registry.
20///
21
22pub struct MemoryRegistryOps;
23
24impl MemoryRegistryOps {
25    /// Initialise registered memory segments and ranges.
26    ///
27    /// - Optionally reserves an initial range for the current crate.
28    /// - Applies all deferred range reservations.
29    /// - Applies all deferred registrations (sorted by ID).
30    pub fn init_memory(
31        initial_range: Option<(&str, u8, u8)>,
32    ) -> Result<MemoryRegistrySummary, MemoryRegistryError> {
33        if let Some((crate_name, start, end)) = initial_range {
34            MemoryRegistry::reserve_range(crate_name, start, end)?;
35        }
36
37        let mut ranges = drain_pending_ranges();
38        ranges.sort_by_key(|(_, start, _)| *start);
39        for (crate_name, start, end) in ranges {
40            MemoryRegistry::reserve_range(crate_name, start, end)?;
41        }
42
43        let mut regs = drain_pending_registrations();
44        regs.sort_by_key(|(id, _, _)| *id);
45        for (id, crate_name, label) in regs {
46            MemoryRegistry::register(id, crate_name, label)?;
47        }
48
49        Ok(MemoryRegistrySummary {
50            ranges: MemoryRegistry::export_ranges(),
51            entries: MemoryRegistry::export(),
52        })
53    }
54
55    #[must_use]
56    pub fn export() -> MemoryRegistryView {
57        MemoryRegistry::export()
58    }
59
60    #[must_use]
61    pub fn export_ranges() -> Vec<(String, MemoryRange)> {
62        MemoryRegistry::export_ranges()
63    }
64
65    #[must_use]
66    pub fn get(id: u8) -> Option<MemoryRegistryEntry> {
67        MemoryRegistry::get(id)
68    }
69}
70
71///
72/// TESTS
73///
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::registry::{defer_register, defer_reserve_range, reset_for_tests};
79
80    #[test]
81    fn init_memory_applies_initial_and_pending() {
82        reset_for_tests();
83        defer_reserve_range("crate_b", 5, 6);
84        defer_register(5, "crate_b", "B5");
85
86        let summary =
87            MemoryRegistryOps::init_memory(Some(("crate_a", 1, 3))).expect("init should succeed");
88
89        assert_eq!(summary.ranges.len(), 2);
90        assert_eq!(summary.entries.len(), 1);
91        assert_eq!(summary.entries[0].0, 5);
92        assert_eq!(summary.entries[0].1.label.as_ref(), "B5");
93    }
94
95    #[test]
96    fn init_memory_is_idempotent_for_same_initial_range() {
97        reset_for_tests();
98
99        MemoryRegistryOps::init_memory(Some(("crate_a", 1, 3))).expect("first init should succeed");
100        MemoryRegistryOps::init_memory(Some(("crate_a", 1, 3)))
101            .expect("second init should succeed");
102    }
103
104    #[test]
105    fn init_memory_returns_error_on_conflict() {
106        reset_for_tests();
107        defer_reserve_range("crate_a", 1, 3);
108        defer_reserve_range("crate_b", 3, 4);
109
110        let err = MemoryRegistryOps::init_memory(None).unwrap_err();
111        matches!(err, MemoryRegistryError::Overlap(_, _, _, _, _, _));
112    }
113}