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, MutexGuard};
10
11#[cfg(test)]
12pub 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 const fn new(record: MemoryManagerAuthorityRecord) -> Self {
75 Self { record }
76 }
77
78 #[must_use]
80 pub fn declaring_crate(&self) -> &str {
81 self.record.authority()
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#[non_exhaustive]
102#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
103pub enum StaticMemoryDeclarationError {
104 #[error("static memory declaration registry lock poisoned")]
106 RegistryPoisoned,
107 #[error("static memory declaration registry is already sealed")]
109 RegistrySealed,
110 #[error(transparent)]
112 Declaration(#[from] crate::DeclarationSnapshotError),
113 #[error(transparent)]
115 Range(#[from] MemoryManagerRangeAuthorityError),
116}
117
118#[derive(Debug, Default)]
119struct StaticMemoryDeclarationRegistry {
120 declarations: Vec<StaticMemoryDeclaration>,
121 ranges: Vec<StaticMemoryRangeDeclaration>,
122 sealed: bool,
123}
124
125static STATIC_MEMORY_DECLARATIONS: Mutex<StaticMemoryDeclarationRegistry> =
126 Mutex::new(StaticMemoryDeclarationRegistry {
127 declarations: Vec::new(),
128 ranges: Vec::new(),
129 sealed: false,
130 });
131
132fn lock_registry()
133-> Result<MutexGuard<'static, StaticMemoryDeclarationRegistry>, StaticMemoryDeclarationError> {
134 STATIC_MEMORY_DECLARATIONS
135 .lock()
136 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)
137}
138
139const fn ensure_unsealed(
140 registry: &StaticMemoryDeclarationRegistry,
141) -> Result<(), StaticMemoryDeclarationError> {
142 if registry.sealed {
143 return Err(StaticMemoryDeclarationError::RegistrySealed);
144 }
145 Ok(())
146}
147
148fn with_unsealed_registry(
149 op: impl FnOnce(&mut StaticMemoryDeclarationRegistry),
150) -> Result<(), StaticMemoryDeclarationError> {
151 let mut registry = lock_registry()?;
152 ensure_unsealed(®istry)?;
153 op(&mut registry);
154 Ok(())
155}
156
157pub fn register_static_memory_declaration(
159 declaring_crate: impl Into<String>,
160 declaration: AllocationDeclaration,
161) -> Result<(), StaticMemoryDeclarationError> {
162 with_unsealed_registry(|registry| {
163 registry
164 .declarations
165 .push(StaticMemoryDeclaration::new(declaring_crate, declaration));
166 })
167}
168
169pub fn register_static_memory_manager_range(
171 start: u8,
172 end: u8,
173 declaring_crate: impl Into<String>,
174 mode: MemoryManagerRangeMode,
175 purpose: Option<String>,
176) -> Result<(), StaticMemoryDeclarationError> {
177 let declaring_crate = declaring_crate.into();
178 let record = MemoryManagerAuthorityRecord::new(
179 MemoryManagerIdRange::new(start, end).map_err(MemoryManagerRangeAuthorityError::Range)?,
180 declaring_crate,
181 mode,
182 purpose,
183 )?;
184 register_static_memory_range_declaration(StaticMemoryRangeDeclaration::new(record))
185}
186
187pub fn register_static_memory_range_declaration(
189 declaration: StaticMemoryRangeDeclaration,
190) -> Result<(), StaticMemoryDeclarationError> {
191 with_unsealed_registry(|registry| {
192 registry.ranges.push(declaration);
193 })
194}
195
196pub fn register_static_memory_manager_declaration(
198 id: u8,
199 declaring_crate: impl Into<String>,
200 label: impl Into<String>,
201 stable_key: impl AsRef<str>,
202) -> Result<(), StaticMemoryDeclarationError> {
203 register_static_memory_manager_declaration_with_schema(
204 id,
205 declaring_crate,
206 label,
207 stable_key,
208 SchemaMetadata::default(),
209 )
210}
211
212pub fn register_static_memory_manager_declaration_with_schema(
214 id: u8,
215 declaring_crate: impl Into<String>,
216 label: impl Into<String>,
217 stable_key: impl AsRef<str>,
218 schema: SchemaMetadata,
219) -> Result<(), StaticMemoryDeclarationError> {
220 let declaration =
221 AllocationDeclaration::memory_manager_with_schema(stable_key, id, label, schema)?;
222 register_static_memory_declaration(declaring_crate, declaration)
223}
224
225pub fn static_memory_declarations()
227-> Result<Vec<StaticMemoryDeclaration>, StaticMemoryDeclarationError> {
228 Ok(lock_registry()?.declarations.clone())
229}
230
231pub fn static_memory_range_declarations()
233-> Result<Vec<StaticMemoryRangeDeclaration>, StaticMemoryDeclarationError> {
234 Ok(lock_registry()?.ranges.clone())
235}
236
237pub fn static_memory_range_authority()
239-> Result<MemoryManagerRangeAuthority, StaticMemoryDeclarationError> {
240 MemoryManagerRangeAuthority::from_records(
241 static_memory_range_declarations()?
242 .into_iter()
243 .map(StaticMemoryRangeDeclaration::into_record)
244 .collect(),
245 )
246 .map_err(StaticMemoryDeclarationError::Range)
247}
248
249pub fn seal_static_memory_registry() -> Result<(), StaticMemoryDeclarationError> {
251 let mut registry = lock_registry()?;
252 registry.sealed = true;
253 Ok(())
254}
255
256pub fn collect_static_memory_declarations(
258 collector: &mut DeclarationCollector,
259) -> Result<(), StaticMemoryDeclarationError> {
260 for registration in static_memory_declarations()? {
261 collector.push(registration.into_declaration());
262 }
263 Ok(())
264}
265
266pub fn static_memory_declaration_snapshot()
272-> Result<DeclarationSnapshot, StaticMemoryDeclarationError> {
273 let declarations = {
274 let mut registry = lock_registry()?;
275 registry.sealed = true;
276 registry
277 .declarations
278 .iter()
279 .map(|registration| registration.declaration.clone())
280 .collect()
281 };
282 DeclarationSnapshot::new(declarations).map_err(StaticMemoryDeclarationError::Declaration)
283}
284
285#[cfg(test)]
286pub fn reset_static_memory_declarations_for_tests() {
287 let mut registry = STATIC_MEMORY_DECLARATIONS
288 .lock()
289 .expect("static memory declaration registry poisoned");
290 registry.declarations.clear();
291 registry.ranges.clear();
292 registry.sealed = false;
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[test]
300 fn registers_and_seals_static_memory_declarations() {
301 let _guard = TEST_REGISTRY_LOCK.lock().expect("test lock poisoned");
302 reset_static_memory_declarations_for_tests();
303
304 register_static_memory_manager_declaration(100, "icydb", "users", "icydb.users.data.v1")
305 .expect("register declaration");
306
307 let registrations = static_memory_declarations().expect("registrations");
308 assert_eq!(registrations.len(), 1);
309 assert_eq!(registrations[0].declaring_crate(), "icydb");
310 assert_eq!(
311 registrations[0].declaration().stable_key().as_str(),
312 "icydb.users.data.v1"
313 );
314
315 let snapshot = static_memory_declaration_snapshot().expect("snapshot");
316 assert_eq!(snapshot.len(), 1);
317
318 let err =
319 register_static_memory_manager_declaration(101, "icydb", "orders", "icydb.orders.v1")
320 .expect_err("late registration must fail");
321 assert_eq!(err, StaticMemoryDeclarationError::RegistrySealed);
322 }
323
324 #[test]
325 fn registers_static_memory_ranges() {
326 let _guard = TEST_REGISTRY_LOCK.lock().expect("test lock poisoned");
327 reset_static_memory_declarations_for_tests();
328
329 register_static_memory_manager_range(
330 100,
331 109,
332 "crate_a",
333 MemoryManagerRangeMode::Reserved,
334 Some("crate A stores".to_string()),
335 )
336 .expect("register range");
337
338 let ranges = static_memory_range_declarations().expect("ranges");
339 assert_eq!(ranges.len(), 1);
340 assert_eq!(ranges[0].declaring_crate(), "crate_a");
341 assert_eq!(ranges[0].record().range().start(), 100);
342 assert_eq!(ranges[0].record().range().end(), 109);
343 }
344
345 #[test]
346 fn static_range_declaration_uses_record_authority() {
347 let record = MemoryManagerAuthorityRecord::new(
348 MemoryManagerIdRange::new(100, 109).expect("range"),
349 "record_authority",
350 MemoryManagerRangeMode::Reserved,
351 None,
352 )
353 .expect("record");
354
355 let range = StaticMemoryRangeDeclaration::new(record);
356
357 assert_eq!(range.declaring_crate(), "record_authority");
358 }
359
360 #[test]
361 fn snapshot_rejects_duplicate_static_memory_declarations() {
362 let _guard = TEST_REGISTRY_LOCK.lock().expect("test lock poisoned");
363 reset_static_memory_declarations_for_tests();
364
365 register_static_memory_manager_declaration(100, "icydb", "users", "icydb.users.data.v1")
366 .expect("register first declaration");
367 register_static_memory_manager_declaration(100, "icydb", "orders", "icydb.orders.v1")
368 .expect("register duplicate slot declaration");
369
370 let err = static_memory_declaration_snapshot().expect_err("duplicate slot must fail");
371 assert!(matches!(
372 err,
373 StaticMemoryDeclarationError::Declaration(
374 crate::DeclarationSnapshotError::DuplicateSlot(_)
375 )
376 ));
377 }
378}