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