1use crate::{
2 constants::DIAGNOSTIC_STRING_MAX_BYTES,
3 declaration::{AllocationDeclaration, DeclarationSnapshot},
4 schema::SchemaMetadata,
5 slot::{
6 IC_MEMORY_AUTHORITY_OWNER, IC_MEMORY_AUTHORITY_PURPOSE, IC_MEMORY_LEDGER_LABEL,
7 IC_MEMORY_LEDGER_STABLE_KEY, MEMORY_MANAGER_GOVERNANCE_MAX_ID, MEMORY_MANAGER_LEDGER_ID,
8 MemoryManagerAuthorityRecord, MemoryManagerIdRange, MemoryManagerRangeAuthority,
9 MemoryManagerRangeAuthorityError, MemoryManagerRangeMode, is_ic_memory_stable_key,
10 },
11};
12use serde::{Deserialize, Serialize};
13use std::{
14 collections::BTreeMap,
15 panic::{AssertUnwindSafe, catch_unwind},
16 sync::{Arc, Mutex, MutexGuard},
17 thread::ThreadId,
18};
19
20#[cfg(test)]
21pub static TEST_REGISTRY_LOCK: Mutex<()> = Mutex::new(());
22
23#[derive(Clone, Debug, Eq, PartialEq)]
34pub struct StaticMemoryDeclaration {
35 authority: String,
36 declaration: AllocationDeclaration,
37}
38
39impl StaticMemoryDeclaration {
40 pub fn new(
42 authority: impl Into<String>,
43 declaration: AllocationDeclaration,
44 ) -> Result<Self, StaticMemoryDeclarationError> {
45 let authority = authority.into();
46 validate_external_authority(&authority)?;
47 declaration.validate()?;
48 if is_ic_memory_stable_key(declaration.stable_key().as_str()) {
49 return Err(StaticMemoryDeclarationError::ReservedStableKey {
50 stable_key: declaration.stable_key().as_str().to_string(),
51 });
52 }
53 Ok(Self {
54 authority,
55 declaration,
56 })
57 }
58
59 #[must_use]
61 pub fn authority(&self) -> &str {
62 &self.authority
63 }
64
65 #[must_use]
67 pub const fn declaration(&self) -> &AllocationDeclaration {
68 &self.declaration
69 }
70
71 #[must_use]
73 pub fn into_declaration(self) -> AllocationDeclaration {
74 self.declaration
75 }
76}
77
78#[derive(Clone, Debug, Eq, PartialEq)]
87pub struct StaticMemoryRangeDeclaration {
88 record: MemoryManagerAuthorityRecord,
89}
90
91impl StaticMemoryRangeDeclaration {
92 pub fn new(record: MemoryManagerAuthorityRecord) -> Result<Self, StaticMemoryDeclarationError> {
94 validate_external_authority(record.authority())?;
95 record.validate()?;
96 Ok(Self { record })
97 }
98
99 #[must_use]
101 pub fn authority(&self) -> &str {
102 self.record.authority()
103 }
104
105 #[must_use]
107 pub const fn record(&self) -> &MemoryManagerAuthorityRecord {
108 &self.record
109 }
110
111 #[must_use]
113 pub fn into_record(self) -> MemoryManagerAuthorityRecord {
114 self.record
115 }
116}
117
118#[non_exhaustive]
123#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
124pub enum StaticMemoryDeclarationError {
125 #[error("static memory declaration registry lock poisoned")]
127 RegistryPoisoned,
128 #[error("static memory declaration registry is already sealed")]
130 RegistrySealed,
131 #[error("static memory declaration snapshot sealing is already active on this thread")]
133 ReentrantSealing,
134 #[error("static memory declaration registry lifecycle is internally inconsistent")]
136 InconsistentLifecycle,
137 #[error("static memory declaration eager-init hook panicked")]
139 EagerInitPanicked,
140 #[error(transparent)]
142 Declaration(#[from] crate::DeclarationSnapshotError),
143 #[error(transparent)]
145 Range(#[from] MemoryManagerRangeAuthorityError),
146 #[error("failed to encode canonical sealed declaration fingerprint material: {message}")]
148 SnapshotFingerprintEncoding {
149 message: String,
151 },
152 #[error("authority {reason}")]
154 InvalidAuthority {
155 reason: &'static str,
157 },
158 #[error("authority '{authority}' is reserved for ic-memory runtime internals")]
160 ReservedAuthority {
161 authority: String,
163 },
164 #[error("stable key '{stable_key}' is reserved for ic-memory runtime internals")]
166 ReservedStableKey {
167 stable_key: String,
169 },
170}
171
172#[derive(Clone, Debug, Eq, PartialEq)]
185pub struct SealedDeclarationSnapshot {
186 inner: Arc<SealedDeclarationSnapshotInner>,
187}
188
189#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
202#[serde(deny_unknown_fields)]
203pub struct SealedDeclarationFingerprint {
204 algorithm_version: u8,
205 value: u64,
206}
207
208impl SealedDeclarationFingerprint {
209 #[must_use]
211 pub const fn algorithm_version(&self) -> u8 {
212 self.algorithm_version
213 }
214
215 #[must_use]
217 pub const fn value(&self) -> u64 {
218 self.value
219 }
220}
221
222#[derive(Debug, Eq, PartialEq)]
223struct SealedDeclarationSnapshotInner {
224 allocation_snapshot: DeclarationSnapshot,
225 registered_declarations: Vec<StaticMemoryDeclaration>,
226 registered_ranges: Vec<StaticMemoryRangeDeclaration>,
227 range_authority: MemoryManagerRangeAuthority,
228 declaration_authority: BTreeMap<String, RuntimeDeclarationAuthority>,
229 fingerprint: SealedDeclarationFingerprint,
230}
231
232#[derive(Clone, Debug, Eq, PartialEq)]
233pub enum RuntimeDeclarationAuthority {
234 Internal,
235 External(String),
236}
237
238impl SealedDeclarationSnapshot {
239 #[must_use]
241 pub fn allocation_snapshot(&self) -> &DeclarationSnapshot {
242 &self.inner.allocation_snapshot
243 }
244
245 #[must_use]
247 pub fn registered_declarations(&self) -> &[StaticMemoryDeclaration] {
248 &self.inner.registered_declarations
249 }
250
251 #[must_use]
253 pub fn registered_ranges(&self) -> &[StaticMemoryRangeDeclaration] {
254 &self.inner.registered_ranges
255 }
256
257 #[must_use]
259 pub fn range_authority(&self) -> &MemoryManagerRangeAuthority {
260 &self.inner.range_authority
261 }
262
263 #[must_use]
265 pub fn fingerprint(&self) -> SealedDeclarationFingerprint {
266 self.inner.fingerprint
267 }
268
269 pub(crate) fn declaration_authority(&self) -> &BTreeMap<String, RuntimeDeclarationAuthority> {
270 &self.inner.declaration_authority
271 }
272
273 pub(crate) fn user_ranges_registered(&self) -> bool {
274 !self.inner.registered_ranges.is_empty()
275 }
276
277 pub(crate) fn shares_storage_with(&self, other: &Self) -> bool {
278 Arc::ptr_eq(&self.inner, &other.inner)
279 }
280}
281
282type StaticRegistrationHook = fn() -> Result<(), StaticMemoryDeclarationError>;
283
284#[derive(Debug)]
285struct StaticMemoryDeclarationRegistry {
286 declarations: Vec<StaticMemoryDeclaration>,
287 ranges: Vec<StaticMemoryRangeDeclaration>,
288 registration_hooks: Vec<StaticRegistrationHook>,
289 eager_init_hooks: Vec<fn()>,
290 lifecycle: StaticRegistryLifecycle,
291}
292
293#[derive(Debug)]
294enum StaticRegistryLifecycle {
295 Open,
296 Sealing {
297 owner: ThreadId,
298 deferred_error: Option<StaticMemoryDeclarationError>,
299 },
300 Sealed(SealedDeclarationSnapshot),
301 Failed(StaticMemoryDeclarationError),
302}
303
304static STATIC_MEMORY_DECLARATIONS: Mutex<StaticMemoryDeclarationRegistry> =
305 Mutex::new(StaticMemoryDeclarationRegistry {
306 declarations: Vec::new(),
307 ranges: Vec::new(),
308 registration_hooks: Vec::new(),
309 eager_init_hooks: Vec::new(),
310 lifecycle: StaticRegistryLifecycle::Open,
311 });
312
313static STATIC_MEMORY_SEAL: Mutex<()> = Mutex::new(());
314
315fn lock_registry()
316-> Result<MutexGuard<'static, StaticMemoryDeclarationRegistry>, StaticMemoryDeclarationError> {
317 STATIC_MEMORY_DECLARATIONS
318 .lock()
319 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)
320}
321
322fn ensure_registration_open(
323 registry: &StaticMemoryDeclarationRegistry,
324) -> Result<(), StaticMemoryDeclarationError> {
325 match ®istry.lifecycle {
326 StaticRegistryLifecycle::Open => Ok(()),
327 StaticRegistryLifecycle::Sealing { owner, .. } if *owner == std::thread::current().id() => {
328 Ok(())
329 }
330 StaticRegistryLifecycle::Sealing { .. }
331 | StaticRegistryLifecycle::Sealed(_)
332 | StaticRegistryLifecycle::Failed(_) => Err(StaticMemoryDeclarationError::RegistrySealed),
333 }
334}
335
336fn with_unsealed_registry(
337 op: impl FnOnce(&mut StaticMemoryDeclarationRegistry),
338) -> Result<(), StaticMemoryDeclarationError> {
339 let mut registry = lock_registry()?;
340 ensure_registration_open(®istry)?;
341 op(&mut registry);
342 Ok(())
343}
344
345#[doc(hidden)]
350pub fn defer_static_memory_registration(hook: StaticRegistrationHook) {
351 defer_constructor_registration(|registry| {
352 registry.registration_hooks.push(hook);
353 });
354}
355
356#[doc(hidden)]
361pub fn defer_eager_init(hook: fn()) {
362 defer_constructor_registration(|registry| {
363 registry.eager_init_hooks.push(hook);
364 });
365}
366
367fn defer_constructor_registration(op: impl FnOnce(&mut StaticMemoryDeclarationRegistry)) {
368 let Ok(mut registry) = STATIC_MEMORY_DECLARATIONS.lock() else {
369 return;
372 };
373 if matches!(registry.lifecycle, StaticRegistryLifecycle::Open) {
374 op(&mut registry);
375 return;
376 }
377 match &mut registry.lifecycle {
378 StaticRegistryLifecycle::Sealing { deferred_error, .. } => {
379 if deferred_error.is_none() {
380 *deferred_error = Some(StaticMemoryDeclarationError::RegistrySealed);
381 }
382 }
383 StaticRegistryLifecycle::Sealed(_) => {
384 registry.lifecycle =
385 StaticRegistryLifecycle::Failed(StaticMemoryDeclarationError::RegistrySealed);
386 }
387 StaticRegistryLifecycle::Failed(_) | StaticRegistryLifecycle::Open => {}
388 }
389}
390
391pub fn register_static_memory_declaration(
393 authority: impl Into<String>,
394 declaration: AllocationDeclaration,
395) -> Result<(), StaticMemoryDeclarationError> {
396 let registration = StaticMemoryDeclaration::new(authority, declaration)?;
397 with_unsealed_registry(|registry| {
398 registry.declarations.push(registration);
399 })
400}
401
402pub fn register_static_memory_manager_range(
404 start: u8,
405 end: u8,
406 authority: impl Into<String>,
407 mode: MemoryManagerRangeMode,
408 purpose: Option<String>,
409) -> Result<(), StaticMemoryDeclarationError> {
410 let authority = authority.into();
411 let record = MemoryManagerAuthorityRecord::new(
412 MemoryManagerIdRange::new(start, end).map_err(MemoryManagerRangeAuthorityError::Range)?,
413 authority,
414 mode,
415 purpose,
416 )?;
417 register_static_memory_range_declaration(StaticMemoryRangeDeclaration::new(record)?)
418}
419
420pub fn register_static_memory_range_declaration(
422 declaration: StaticMemoryRangeDeclaration,
423) -> Result<(), StaticMemoryDeclarationError> {
424 validate_external_authority(declaration.authority())?;
425 with_unsealed_registry(|registry| {
426 registry.ranges.push(declaration);
427 })
428}
429
430fn validate_external_authority(value: &str) -> Result<(), StaticMemoryDeclarationError> {
431 if value == IC_MEMORY_AUTHORITY_OWNER {
432 return Err(StaticMemoryDeclarationError::ReservedAuthority {
433 authority: value.to_string(),
434 });
435 }
436 if value.is_empty() {
437 return Err(StaticMemoryDeclarationError::InvalidAuthority {
438 reason: "must not be empty",
439 });
440 }
441 if value.len() > DIAGNOSTIC_STRING_MAX_BYTES {
442 return Err(StaticMemoryDeclarationError::InvalidAuthority {
443 reason: "must be at most 256 bytes",
444 });
445 }
446 if !value.is_ascii() {
447 return Err(StaticMemoryDeclarationError::InvalidAuthority {
448 reason: "must be ASCII",
449 });
450 }
451 if value.bytes().any(|byte| byte.is_ascii_control()) {
452 return Err(StaticMemoryDeclarationError::InvalidAuthority {
453 reason: "must not contain ASCII control characters",
454 });
455 }
456 Ok(())
457}
458
459pub fn register_static_memory_manager_declaration(
461 id: u8,
462 authority: impl Into<String>,
463 label: impl Into<String>,
464 stable_key: impl AsRef<str>,
465) -> Result<(), StaticMemoryDeclarationError> {
466 register_static_memory_manager_declaration_with_schema(
467 id,
468 authority,
469 label,
470 stable_key,
471 SchemaMetadata::default(),
472 )
473}
474
475pub fn register_static_memory_manager_declaration_with_schema(
477 id: u8,
478 authority: impl Into<String>,
479 label: impl Into<String>,
480 stable_key: impl AsRef<str>,
481 schema: SchemaMetadata,
482) -> Result<(), StaticMemoryDeclarationError> {
483 let declaration =
484 AllocationDeclaration::memory_manager_with_schema(stable_key, id, label, schema)?;
485 register_static_memory_declaration(authority, declaration)
486}
487
488pub fn sealed_declaration_snapshot()
495-> Result<SealedDeclarationSnapshot, StaticMemoryDeclarationError> {
496 {
497 let registry = lock_registry()?;
498 match ®istry.lifecycle {
499 StaticRegistryLifecycle::Sealed(snapshot) => return Ok(snapshot.clone()),
500 StaticRegistryLifecycle::Failed(err) => return Err(err.clone()),
501 StaticRegistryLifecycle::Sealing { owner, .. }
502 if *owner == std::thread::current().id() =>
503 {
504 return Err(StaticMemoryDeclarationError::ReentrantSealing);
505 }
506 StaticRegistryLifecycle::Open | StaticRegistryLifecycle::Sealing { .. } => {}
507 }
508 }
509
510 let _seal = STATIC_MEMORY_SEAL
511 .lock()
512 .map_err(|_| StaticMemoryDeclarationError::RegistryPoisoned)?;
513 let (registration_hooks, eager_init_hooks) = {
514 let mut registry = lock_registry()?;
515 match ®istry.lifecycle {
516 StaticRegistryLifecycle::Sealed(snapshot) => return Ok(snapshot.clone()),
517 StaticRegistryLifecycle::Failed(err) => return Err(err.clone()),
518 StaticRegistryLifecycle::Sealing { .. } => {
519 return Err(StaticMemoryDeclarationError::ReentrantSealing);
520 }
521 StaticRegistryLifecycle::Open => {}
522 }
523 registry.lifecycle = StaticRegistryLifecycle::Sealing {
524 owner: std::thread::current().id(),
525 deferred_error: None,
526 };
527 (
528 std::mem::take(&mut registry.registration_hooks),
529 std::mem::take(&mut registry.eager_init_hooks),
530 )
531 };
532
533 for hook in registration_hooks {
534 let result = catch_unwind(AssertUnwindSafe(hook))
535 .map_err(|_| StaticMemoryDeclarationError::EagerInitPanicked)
536 .and_then(std::convert::identity);
537 if let Err(err) = result {
538 return fail_sealing(err);
539 }
540 }
541 for hook in eager_init_hooks {
542 if catch_unwind(AssertUnwindSafe(hook)).is_err() {
543 return fail_sealing(StaticMemoryDeclarationError::EagerInitPanicked);
544 }
545 }
546
547 let mut registry = lock_registry()?;
548 let deferred_error = match ®istry.lifecycle {
549 StaticRegistryLifecycle::Sealing { deferred_error, .. } => deferred_error.clone(),
550 StaticRegistryLifecycle::Failed(err) => return Err(err.clone()),
551 StaticRegistryLifecycle::Open | StaticRegistryLifecycle::Sealed(_) => {
552 return Err(StaticMemoryDeclarationError::InconsistentLifecycle);
553 }
554 };
555 if let Some(err) = deferred_error {
556 registry.lifecycle = StaticRegistryLifecycle::Failed(err.clone());
557 return Err(err);
558 }
559 let snapshot = match build_sealed_snapshot(®istry.declarations, ®istry.ranges) {
560 Ok(snapshot) => snapshot,
561 Err(err) => {
562 registry.lifecycle = StaticRegistryLifecycle::Failed(err.clone());
563 return Err(err);
564 }
565 };
566 registry.lifecycle = StaticRegistryLifecycle::Sealed(snapshot.clone());
567 Ok(snapshot)
568}
569
570fn fail_sealing<T>(err: StaticMemoryDeclarationError) -> Result<T, StaticMemoryDeclarationError> {
571 let mut registry = lock_registry()?;
572 let failure = match ®istry.lifecycle {
573 StaticRegistryLifecycle::Sealing {
574 deferred_error: Some(deferred_error),
575 ..
576 } => deferred_error.clone(),
577 StaticRegistryLifecycle::Open
578 | StaticRegistryLifecycle::Sealing {
579 deferred_error: None,
580 ..
581 }
582 | StaticRegistryLifecycle::Sealed(_) => err,
583 StaticRegistryLifecycle::Failed(failure) => failure.clone(),
584 };
585 registry.lifecycle = StaticRegistryLifecycle::Failed(failure.clone());
586 Err(failure)
587}
588
589fn build_sealed_snapshot(
590 declarations: &[StaticMemoryDeclaration],
591 ranges: &[StaticMemoryRangeDeclaration],
592) -> Result<SealedDeclarationSnapshot, StaticMemoryDeclarationError> {
593 let mut registered_declarations = declarations.to_vec();
594 registered_declarations.sort_by(|left, right| {
595 left.declaration()
596 .stable_key()
597 .cmp(right.declaration().stable_key())
598 .then_with(|| left.declaration().slot().cmp(right.declaration().slot()))
599 .then_with(|| left.authority().cmp(right.authority()))
600 });
601
602 let mut registered_ranges = ranges.to_vec();
603 registered_ranges.sort_by(|left, right| {
604 let left = left.record();
605 let right = right.record();
606 left.range()
607 .start()
608 .cmp(&right.range().start())
609 .then_with(|| left.range().end().cmp(&right.range().end()))
610 .then_with(|| left.authority().cmp(right.authority()))
611 .then_with(|| range_mode_order(left.mode()).cmp(&range_mode_order(right.mode())))
612 .then_with(|| left.purpose().cmp(&right.purpose()))
613 });
614
615 let mut allocation_declarations = Vec::with_capacity(registered_declarations.len() + 1);
616 allocation_declarations.push(internal_ledger_declaration()?);
617 allocation_declarations.extend(
618 registered_declarations
619 .iter()
620 .map(|registration| registration.declaration().clone()),
621 );
622 let allocation_snapshot = DeclarationSnapshot::new(allocation_declarations)?;
623
624 let mut authority_records = Vec::with_capacity(registered_ranges.len() + 1);
625 authority_records.push(internal_ledger_range()?);
626 authority_records.extend(
627 registered_ranges
628 .iter()
629 .map(|registration| registration.record().clone()),
630 );
631 let range_authority = MemoryManagerRangeAuthority::from_records(authority_records)?;
632 let fingerprint = sealed_declaration_fingerprint(
633 &allocation_snapshot,
634 ®istered_declarations,
635 range_authority.authorities(),
636 )?;
637
638 let mut declaration_authority = BTreeMap::new();
639 declaration_authority.insert(
640 IC_MEMORY_LEDGER_STABLE_KEY.to_string(),
641 RuntimeDeclarationAuthority::Internal,
642 );
643 for registration in ®istered_declarations {
644 declaration_authority.insert(
645 registration.declaration().stable_key().as_str().to_string(),
646 RuntimeDeclarationAuthority::External(registration.authority().to_string()),
647 );
648 }
649
650 Ok(SealedDeclarationSnapshot {
651 inner: Arc::new(SealedDeclarationSnapshotInner {
652 allocation_snapshot,
653 registered_declarations,
654 registered_ranges,
655 range_authority,
656 declaration_authority,
657 fingerprint,
658 }),
659 })
660}
661
662#[derive(Serialize)]
663struct FingerprintDeclaration<'a> {
664 authority: &'a str,
665 declaration: &'a AllocationDeclaration,
666}
667
668#[derive(Serialize)]
669struct SealedDeclarationFingerprintMaterial<'a> {
670 format: &'static str,
671 allocation_snapshot: &'a DeclarationSnapshot,
672 registered_declarations: Vec<FingerprintDeclaration<'a>>,
673 effective_ranges: &'a [MemoryManagerAuthorityRecord],
674}
675
676fn sealed_declaration_fingerprint(
677 allocation_snapshot: &DeclarationSnapshot,
678 registered_declarations: &[StaticMemoryDeclaration],
679 effective_ranges: &[MemoryManagerAuthorityRecord],
680) -> Result<SealedDeclarationFingerprint, StaticMemoryDeclarationError> {
681 let material = SealedDeclarationFingerprintMaterial {
682 format: "ic-memory.sealed-declaration-fingerprint.v1",
683 allocation_snapshot,
684 registered_declarations: registered_declarations
685 .iter()
686 .map(|registration| FingerprintDeclaration {
687 authority: registration.authority(),
688 declaration: registration.declaration(),
689 })
690 .collect(),
691 effective_ranges,
692 };
693 let mut bytes = Vec::new();
694 ciborium::into_writer(&material, &mut bytes).map_err(|err| {
695 StaticMemoryDeclarationError::SnapshotFingerprintEncoding {
696 message: err.to_string(),
697 }
698 })?;
699
700 let value = bytes
701 .into_iter()
702 .fold(FINGERPRINT_FNV_OFFSET, fingerprint_hash_byte);
703 Ok(SealedDeclarationFingerprint {
704 algorithm_version: SEALED_DECLARATION_FINGERPRINT_VERSION,
705 value,
706 })
707}
708
709const SEALED_DECLARATION_FINGERPRINT_VERSION: u8 = 1;
710const FINGERPRINT_FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
711const FINGERPRINT_FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
712
713const fn fingerprint_hash_byte(hash: u64, byte: u8) -> u64 {
714 (hash ^ byte as u64).wrapping_mul(FINGERPRINT_FNV_PRIME)
715}
716
717const fn range_mode_order(mode: MemoryManagerRangeMode) -> u8 {
718 match mode {
719 MemoryManagerRangeMode::Reserved => 0,
720 MemoryManagerRangeMode::Allowed => 1,
721 }
722}
723
724fn internal_ledger_declaration() -> Result<AllocationDeclaration, crate::DeclarationSnapshotError> {
725 AllocationDeclaration::memory_manager(
726 IC_MEMORY_LEDGER_STABLE_KEY,
727 MEMORY_MANAGER_LEDGER_ID,
728 IC_MEMORY_LEDGER_LABEL,
729 )
730}
731
732fn internal_ledger_range() -> Result<MemoryManagerAuthorityRecord, MemoryManagerRangeAuthorityError>
733{
734 MemoryManagerAuthorityRecord::new(
735 MemoryManagerIdRange::new(MEMORY_MANAGER_LEDGER_ID, MEMORY_MANAGER_GOVERNANCE_MAX_ID)?,
736 IC_MEMORY_AUTHORITY_OWNER,
737 MemoryManagerRangeMode::Reserved,
738 Some(IC_MEMORY_AUTHORITY_PURPOSE.to_string()),
739 )
740}
741
742#[cfg(test)]
743pub fn reset_static_memory_declarations_for_tests() {
744 let mut registry = STATIC_MEMORY_DECLARATIONS
745 .lock()
746 .expect("static memory declaration registry poisoned");
747 registry.declarations.clear();
748 registry.ranges.clear();
749 registry.registration_hooks.clear();
750 registry.eager_init_hooks.clear();
751 registry.lifecycle = StaticRegistryLifecycle::Open;
752}
753
754#[cfg(test)]
755mod tests;