1use crate::{
2 declaration::{AllocationDeclaration, DeclarationCollector, DeclarationSnapshot},
3 schema::SchemaMetadata,
4 slot::{
5 MemoryManagerAuthorityRecord, MemoryManagerIdRange, MemoryManagerRangeAuthority,
6 MemoryManagerRangeAuthorityError, MemoryManagerRangeMode,
7 },
8};
9use std::sync::Mutex;
10
11#[cfg(test)]
12pub(crate) static TEST_REGISTRY_LOCK: Mutex<()> = Mutex::new(());
13
14#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct StaticMemoryDeclaration {
26 declaring_crate: String,
27 declaration: AllocationDeclaration,
28}
29
30impl StaticMemoryDeclaration {
31 pub fn new(declaring_crate: impl Into<String>, declaration: AllocationDeclaration) -> Self {
33 Self {
34 declaring_crate: declaring_crate.into(),
35 declaration,
36 }
37 }
38
39 #[must_use]
41 pub fn declaring_crate(&self) -> &str {
42 &self.declaring_crate
43 }
44
45 #[must_use]
47 pub const fn declaration(&self) -> &AllocationDeclaration {
48 &self.declaration
49 }
50
51 #[must_use]
53 pub fn into_declaration(self) -> AllocationDeclaration {
54 self.declaration
55 }
56}
57
58#[derive(Clone, Debug, Eq, PartialEq)]
67pub struct StaticMemoryRangeDeclaration {
68 record: MemoryManagerAuthorityRecord,
69}
70
71impl StaticMemoryRangeDeclaration {
72 #[must_use]
74 pub fn new(declaring_crate: impl Into<String>, record: MemoryManagerAuthorityRecord) -> Self {
75 let declaring_crate = declaring_crate.into();
76 debug_assert_eq!(declaring_crate, record.authority);
77 Self { record }
78 }
79
80 #[must_use]
82 pub fn declaring_crate(&self) -> &str {
83 &self.record.authority
84 }
85
86 #[must_use]
88 pub const fn record(&self) -> &MemoryManagerAuthorityRecord {
89 &self.record
90 }
91
92 #[must_use]
94 pub fn into_record(self) -> MemoryManagerAuthorityRecord {
95 self.record
96 }
97}
98
99#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
104pub enum StaticMemoryDeclarationError {
105 #[error("static memory declaration registry lock poisoned")]
107 RegistryPoisoned,
108 #[error("static memory declaration registry is already sealed")]
110 RegistrySealed,
111 #[error(transparent)]
113 Declaration(#[from] crate::DeclarationSnapshotError),
114 #[error(transparent)]
116 Range(#[from] MemoryManagerRangeAuthorityError),
117}
118
119#[derive(Debug, Default)]
120struct StaticMemoryDeclarationRegistry {
121 declarations: Vec<StaticMemoryDeclaration>,
122 ranges: Vec<StaticMemoryRangeDeclaration>,
123 sealed: bool,
124}
125
126static STATIC_MEMORY_DECLARATIONS: Mutex<StaticMemoryDeclarationRegistry> =
127 Mutex::new(StaticMemoryDeclarationRegistry {
128 declarations: Vec::new(),
129 ranges: Vec::new(),
130 sealed: false,
131 });
132
133pub fn register_static_memory_declaration(
135 declaring_crate: impl Into<String>,
136 declaration: AllocationDeclaration,
137) -> Result<(), StaticMemoryDeclarationError> {
138 let mut registry = STATIC_MEMORY_DECLARATIONS
139 .lock()
140 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)?;
141 if registry.sealed {
142 return Err(StaticMemoryDeclarationError::RegistrySealed);
143 }
144 registry
145 .declarations
146 .push(StaticMemoryDeclaration::new(declaring_crate, declaration));
147 Ok(())
148}
149
150pub fn register_static_memory_manager_range(
152 start: u8,
153 end: u8,
154 declaring_crate: impl Into<String>,
155 mode: MemoryManagerRangeMode,
156 purpose: Option<String>,
157) -> Result<(), StaticMemoryDeclarationError> {
158 let declaring_crate = declaring_crate.into();
159 let record = MemoryManagerAuthorityRecord::new(
160 MemoryManagerIdRange::new(start, end).map_err(MemoryManagerRangeAuthorityError::Range)?,
161 declaring_crate.clone(),
162 mode,
163 purpose,
164 )?;
165 register_static_memory_range_declaration(StaticMemoryRangeDeclaration::new(
166 declaring_crate,
167 record,
168 ))
169}
170
171pub fn register_static_memory_range_declaration(
173 declaration: StaticMemoryRangeDeclaration,
174) -> Result<(), StaticMemoryDeclarationError> {
175 let mut registry = STATIC_MEMORY_DECLARATIONS
176 .lock()
177 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)?;
178 if registry.sealed {
179 return Err(StaticMemoryDeclarationError::RegistrySealed);
180 }
181 registry.ranges.push(declaration);
182 Ok(())
183}
184
185pub fn register_static_memory_manager_declaration(
187 id: u8,
188 declaring_crate: impl Into<String>,
189 label: impl Into<String>,
190 stable_key: impl AsRef<str>,
191) -> Result<(), StaticMemoryDeclarationError> {
192 register_static_memory_manager_declaration_with_schema(
193 id,
194 declaring_crate,
195 label,
196 stable_key,
197 SchemaMetadata::default(),
198 )
199}
200
201pub fn register_static_memory_manager_declaration_with_schema(
203 id: u8,
204 declaring_crate: impl Into<String>,
205 label: impl Into<String>,
206 stable_key: impl AsRef<str>,
207 schema: SchemaMetadata,
208) -> Result<(), StaticMemoryDeclarationError> {
209 let declaration =
210 AllocationDeclaration::memory_manager_with_schema(stable_key, id, label, schema)?;
211 register_static_memory_declaration(declaring_crate, declaration)
212}
213
214pub fn static_memory_declarations()
216-> Result<Vec<StaticMemoryDeclaration>, StaticMemoryDeclarationError> {
217 STATIC_MEMORY_DECLARATIONS
218 .lock()
219 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)
220 .map(|registry| registry.declarations.clone())
221}
222
223pub fn static_memory_range_declarations()
225-> Result<Vec<StaticMemoryRangeDeclaration>, StaticMemoryDeclarationError> {
226 STATIC_MEMORY_DECLARATIONS
227 .lock()
228 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)
229 .map(|registry| registry.ranges.clone())
230}
231
232pub fn static_memory_range_authority()
234-> Result<MemoryManagerRangeAuthority, StaticMemoryDeclarationError> {
235 MemoryManagerRangeAuthority::from_records(
236 static_memory_range_declarations()?
237 .into_iter()
238 .map(StaticMemoryRangeDeclaration::into_record)
239 .collect(),
240 )
241 .map_err(StaticMemoryDeclarationError::Range)
242}
243
244pub(crate) fn seal_static_memory_registry() -> Result<(), StaticMemoryDeclarationError> {
246 let mut registry = STATIC_MEMORY_DECLARATIONS
247 .lock()
248 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)?;
249 registry.sealed = true;
250 Ok(())
251}
252
253pub fn collect_static_memory_declarations(
255 collector: &mut DeclarationCollector,
256) -> Result<(), StaticMemoryDeclarationError> {
257 for registration in static_memory_declarations()? {
258 collector.push(registration.into_declaration());
259 }
260 Ok(())
261}
262
263pub fn static_memory_declaration_snapshot()
269-> Result<DeclarationSnapshot, StaticMemoryDeclarationError> {
270 let declarations = {
271 let mut registry = STATIC_MEMORY_DECLARATIONS
272 .lock()
273 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)?;
274 registry.sealed = true;
275 registry
276 .declarations
277 .iter()
278 .map(|registration| registration.declaration.clone())
279 .collect()
280 };
281 DeclarationSnapshot::new(declarations).map_err(StaticMemoryDeclarationError::Declaration)
282}
283
284#[cfg(test)]
285pub(crate) fn reset_static_memory_declarations_for_tests() {
286 let mut registry = STATIC_MEMORY_DECLARATIONS
287 .lock()
288 .expect("static memory declaration registry poisoned");
289 registry.declarations.clear();
290 registry.ranges.clear();
291 registry.sealed = false;
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn registers_and_seals_static_memory_declarations() {
300 let _guard = TEST_REGISTRY_LOCK.lock().expect("test lock poisoned");
301 reset_static_memory_declarations_for_tests();
302
303 register_static_memory_manager_declaration(100, "icydb", "users", "icydb.users.data.v1")
304 .expect("register declaration");
305
306 let registrations = static_memory_declarations().expect("registrations");
307 assert_eq!(registrations.len(), 1);
308 assert_eq!(registrations[0].declaring_crate(), "icydb");
309 assert_eq!(
310 registrations[0].declaration().stable_key().as_str(),
311 "icydb.users.data.v1"
312 );
313
314 let snapshot = static_memory_declaration_snapshot().expect("snapshot");
315 assert_eq!(snapshot.len(), 1);
316
317 let err =
318 register_static_memory_manager_declaration(101, "icydb", "orders", "icydb.orders.v1")
319 .expect_err("late registration must fail");
320 assert_eq!(err, StaticMemoryDeclarationError::RegistrySealed);
321 }
322
323 #[test]
324 fn registers_static_memory_ranges() {
325 let _guard = TEST_REGISTRY_LOCK.lock().expect("test lock poisoned");
326 reset_static_memory_declarations_for_tests();
327
328 register_static_memory_manager_range(
329 100,
330 109,
331 "crate_a",
332 MemoryManagerRangeMode::Reserved,
333 Some("crate A stores".to_string()),
334 )
335 .expect("register range");
336
337 let ranges = static_memory_range_declarations().expect("ranges");
338 assert_eq!(ranges.len(), 1);
339 assert_eq!(ranges[0].declaring_crate(), "crate_a");
340 assert_eq!(ranges[0].record().range.start(), 100);
341 assert_eq!(ranges[0].record().range.end(), 109);
342 }
343
344 #[test]
345 fn snapshot_rejects_duplicate_static_memory_declarations() {
346 let _guard = TEST_REGISTRY_LOCK.lock().expect("test lock poisoned");
347 reset_static_memory_declarations_for_tests();
348
349 register_static_memory_manager_declaration(100, "icydb", "users", "icydb.users.data.v1")
350 .expect("register first declaration");
351 register_static_memory_manager_declaration(100, "icydb", "orders", "icydb.orders.v1")
352 .expect("register duplicate slot declaration");
353
354 let err = static_memory_declaration_snapshot().expect_err("duplicate slot must fail");
355 assert!(matches!(
356 err,
357 StaticMemoryDeclarationError::Declaration(
358 crate::DeclarationSnapshotError::DuplicateSlot(_)
359 )
360 ));
361 }
362}