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