canic_core/memory/admission/
mod.rs1use crate::memory::registry::MemoryRegistryError;
8use ic_memory::BootstrapAdmission;
9use std::sync::Mutex;
10
11pub use ic_memory::PolicyIdentity;
12
13#[derive(Clone, Debug)]
19pub struct MemoryBootstrapAdmission {
20 pub(super) identity: PolicyIdentity,
21 pub(super) prepare: fn(&mut BootstrapAdmission<'_>) -> Result<(), MemoryRegistryError>,
22}
23
24impl MemoryBootstrapAdmission {
25 #[must_use]
27 pub const fn new(
28 identity: PolicyIdentity,
29 prepare: fn(&mut BootstrapAdmission<'_>) -> Result<(), MemoryRegistryError>,
30 ) -> Self {
31 Self { identity, prepare }
32 }
33}
34
35#[derive(Default)]
36struct Registration {
37 participant: Option<MemoryBootstrapAdmission>,
38 sealed: bool,
39}
40
41impl Registration {
42 fn register(
43 &mut self,
44 participant: MemoryBootstrapAdmission,
45 ) -> Result<(), MemoryRegistryError> {
46 if self.sealed {
47 return Err(MemoryRegistryError::AdmissionRegistrationSealed);
48 }
49 if self.participant.is_some() {
50 return Err(MemoryRegistryError::AdmissionAlreadyRegistered);
51 }
52 self.participant = Some(participant);
53 Ok(())
54 }
55
56 fn seal(&mut self) -> Option<MemoryBootstrapAdmission> {
57 self.sealed = true;
58 self.participant.clone()
59 }
60}
61
62static ADMISSION: Mutex<Registration> = Mutex::new(Registration {
63 participant: None,
64 sealed: false,
65});
66
67#[doc(hidden)]
72pub fn register(participant: MemoryBootstrapAdmission) -> Result<(), MemoryRegistryError> {
73 ADMISSION
74 .lock()
75 .map_err(|_| MemoryRegistryError::AdmissionRegistryPoisoned)?
76 .register(participant)
77}
78
79pub(super) fn seal() -> Result<Option<MemoryBootstrapAdmission>, MemoryRegistryError> {
80 Ok(ADMISSION
81 .lock()
82 .map_err(|_| MemoryRegistryError::AdmissionRegistryPoisoned)?
83 .seal())
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 fn participant() -> MemoryBootstrapAdmission {
91 MemoryBootstrapAdmission::new(
92 PolicyIdentity::new("test.admission", 1).unwrap(),
93 |_| Ok(()),
94 )
95 }
96
97 #[test]
98 fn registration_is_single_and_sealed_even_without_a_participant() {
99 let mut registration = Registration::default();
100 registration.register(participant()).unwrap();
101 assert!(matches!(
102 registration.register(participant()),
103 Err(MemoryRegistryError::AdmissionAlreadyRegistered)
104 ));
105 assert!(registration.seal().is_some());
106 assert!(registration.seal().is_some());
107 assert!(matches!(
108 registration.register(participant()),
109 Err(MemoryRegistryError::AdmissionRegistrationSealed)
110 ));
111 let mut absent = Registration::default();
112 assert!(absent.seal().is_none());
113 assert!(matches!(
114 absent.register(participant()),
115 Err(MemoryRegistryError::AdmissionRegistrationSealed)
116 ));
117 }
118}