1use crate::{
2 key::{StableKey, StableKeyError},
3 schema::SchemaMetadata,
4 slot::{MemoryManagerSlot, MemoryManagerSlotError},
5};
6use serde::{Deserialize, Deserializer, Serialize, de::Error as _};
7
8#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
20#[serde(deny_unknown_fields)]
21pub struct AllocationDeclaration {
22 pub(crate) stable_key: StableKey,
24 pub(crate) slot: MemoryManagerSlot,
26 pub(crate) schema: SchemaMetadata,
28}
29
30impl AllocationDeclaration {
31 pub fn new(
33 stable_key: impl AsRef<str>,
34 slot: MemoryManagerSlot,
35 schema: SchemaMetadata,
36 ) -> Result<Self, DeclarationSnapshotError> {
37 let stable_key = StableKey::parse(stable_key).map_err(DeclarationSnapshotError::Key)?;
38 Ok(Self {
39 stable_key,
40 slot,
41 schema,
42 })
43 }
44
45 pub fn memory_manager(
47 stable_key: impl AsRef<str>,
48 id: u8,
49 ) -> Result<Self, DeclarationSnapshotError> {
50 Self::memory_manager_with_schema(stable_key, id, SchemaMetadata::default())
51 }
52
53 pub fn memory_manager_with_schema(
55 stable_key: impl AsRef<str>,
56 id: u8,
57 schema: SchemaMetadata,
58 ) -> Result<Self, DeclarationSnapshotError> {
59 let slot =
60 MemoryManagerSlot::new(id).map_err(DeclarationSnapshotError::MemoryManagerSlot)?;
61 Self::new(stable_key, slot, schema)
62 }
63
64 #[must_use]
66 pub const fn stable_key(&self) -> &StableKey {
67 &self.stable_key
68 }
69
70 #[must_use]
72 pub const fn slot(&self) -> &MemoryManagerSlot {
73 &self.slot
74 }
75
76 #[must_use]
78 pub const fn schema(&self) -> &SchemaMetadata {
79 &self.schema
80 }
81}
82
83#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
95pub struct DeclarationSnapshot {
96 declarations: Vec<AllocationDeclaration>,
98}
99
100impl<'de> Deserialize<'de> for DeclarationSnapshot {
101 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
102 #[derive(Deserialize)]
103 #[serde(rename = "DeclarationSnapshot", deny_unknown_fields)]
104 struct Snapshot {
105 #[serde(deserialize_with = "crate::cbor::deserialize_records")]
106 declarations: Vec<AllocationDeclaration>,
107 }
108
109 let snapshot = Snapshot::deserialize(deserializer)?;
110 Self::new(snapshot.declarations).map_err(D::Error::custom)
111 }
112}
113
114impl DeclarationSnapshot {
115 pub fn new(declarations: Vec<AllocationDeclaration>) -> Result<Self, DeclarationSnapshotError> {
117 validate_declaration_set(&declarations)?;
118 Ok(Self { declarations })
119 }
120
121 pub(crate) fn canonicalize(
124 mut declarations: Vec<AllocationDeclaration>,
125 ) -> Result<Self, DeclarationSnapshotError> {
126 if declarations.len() > crate::constants::MAX_ALLOCATIONS {
127 return Err(DeclarationSnapshotError::TooManyDeclarations);
128 }
129 crate::sort::sort_unstable_by(&mut declarations, |a, b| a.stable_key.cmp(&b.stable_key));
130 let mut duplicate_keys = [false; crate::constants::MAX_ALLOCATIONS];
131 for (index, pair) in declarations.windows(2).enumerate() {
132 duplicate_keys[index + 1] = pair[0].stable_key == pair[1].stable_key;
133 }
134 validate_declaration_identities(&declarations, &duplicate_keys)?;
135 Ok(Self { declarations })
136 }
137
138 #[must_use]
140 pub const fn is_empty(&self) -> bool {
141 self.declarations.is_empty()
142 }
143
144 #[must_use]
146 pub const fn len(&self) -> usize {
147 self.declarations.len()
148 }
149
150 #[must_use]
152 pub fn declarations(&self) -> &[AllocationDeclaration] {
153 &self.declarations
154 }
155
156 pub(crate) fn into_declarations(self) -> Vec<AllocationDeclaration> {
157 self.declarations
158 }
159}
160
161#[non_exhaustive]
166#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
167pub enum DeclarationSnapshotError {
168 #[error("at most 255 allocation declarations are supported")]
169 TooManyDeclarations,
170 #[error(transparent)]
172 Key(StableKeyError),
173 #[error(transparent)]
175 MemoryManagerSlot(MemoryManagerSlotError),
176 #[error("stable key '{0}' is declared more than once")]
178 DuplicateStableKey(StableKey),
179 #[error("allocation slot '{0:?}' is declared more than once")]
181 DuplicateSlot(MemoryManagerSlot),
182}
183
184fn validate_declaration_set(
185 declarations: &[AllocationDeclaration],
186) -> Result<(), DeclarationSnapshotError> {
187 if declarations.len() > crate::constants::MAX_ALLOCATIONS {
188 return Err(DeclarationSnapshotError::TooManyDeclarations);
189 }
190 let duplicate_keys = crate::key::duplicate_key_positions(
191 declarations
192 .iter()
193 .enumerate()
194 .map(|(index, declaration)| (&declaration.stable_key, index))
195 .collect(),
196 );
197 validate_declaration_identities(declarations, &duplicate_keys)
198}
199
200fn validate_declaration_identities(
201 declarations: &[AllocationDeclaration],
202 duplicate_keys: &[bool; crate::constants::MAX_ALLOCATIONS],
203) -> Result<(), DeclarationSnapshotError> {
204 let mut slots = [false; crate::constants::MAX_ALLOCATIONS];
205
206 for (index, declaration) in declarations.iter().enumerate() {
207 let occupied = &mut slots[usize::from(declaration.slot.id())];
208 if *occupied {
209 return Err(DeclarationSnapshotError::DuplicateSlot(
210 declaration.slot.clone(),
211 ));
212 }
213 *occupied = true;
214 if duplicate_keys[index] {
215 return Err(DeclarationSnapshotError::DuplicateStableKey(
216 declaration.stable_key.clone(),
217 ));
218 }
219 }
220
221 Ok(())
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227 use crate::slot::MemoryManagerSlot;
228
229 fn declaration(key: &str, id: u8) -> AllocationDeclaration {
230 AllocationDeclaration::new(
231 key,
232 MemoryManagerSlot::new(id).expect("usable slot"),
233 SchemaMetadata::default(),
234 )
235 .expect("declaration")
236 }
237
238 #[test]
239 fn memory_manager_declaration_constructor_builds_common_declaration() {
240 let declaration =
241 AllocationDeclaration::memory_manager("app.orders.v1", 100).expect("declaration");
242
243 assert_eq!(declaration.stable_key.as_str(), "app.orders.v1");
244 assert_eq!(
245 declaration.slot,
246 MemoryManagerSlot::new(100).expect("usable slot")
247 );
248 assert_eq!(declaration.schema, SchemaMetadata::default());
249 }
250
251 #[test]
252 fn memory_manager_declaration_constructor_rejects_invalid_slot() {
253 let err = AllocationDeclaration::memory_manager("app.orders.v1", u8::MAX)
254 .expect_err("sentinel must fail");
255
256 assert!(matches!(
257 err,
258 DeclarationSnapshotError::MemoryManagerSlot(_)
259 ));
260 }
261
262 #[test]
263 fn snapshot_decode_rejects_unusable_memory_manager_slot() {
264 let snapshot = DeclarationSnapshot::new(vec![declaration("app.orders.v1", 100)]).unwrap();
265 let mut value = serde_json::to_value(snapshot).unwrap();
266 value["declarations"][0]["slot"] = serde_json::json!(255);
267 assert!(serde_json::from_value::<DeclarationSnapshot>(value).is_err());
268 }
269
270 #[test]
271 fn rejects_duplicate_keys() {
272 let err = DeclarationSnapshot::new(vec![
273 declaration("app.users.v1", 100),
274 declaration("app.users.v1", 101),
275 ])
276 .expect_err("duplicate key");
277
278 assert_eq!(
279 err,
280 DeclarationSnapshotError::DuplicateStableKey(StableKey::parse("app.users.v1").unwrap())
281 );
282 }
283
284 #[test]
285 fn rejects_duplicate_slots() {
286 for second_key in ["app.orders.v1", "app.users.v1"] {
287 let err = DeclarationSnapshot::new(vec![
288 declaration("app.users.v1", 100),
289 declaration(second_key, 100),
290 ])
291 .expect_err("duplicate slot precedes duplicate key");
292
293 assert_eq!(
294 err,
295 DeclarationSnapshotError::DuplicateSlot(MemoryManagerSlot::new(100).unwrap())
296 );
297 }
298 }
299
300 #[test]
301 fn canonical_resolution_preserves_identity_failures_and_bounds() {
302 let choices = [
305 ("app.a.v1", 10),
306 ("app.a.v1", 11),
307 ("app.b.v1", 10),
308 ("app.b.v1", 11),
309 ];
310 for code in 0..256 {
311 let mut code = code;
312 let input: Vec<_> = (0..4)
313 .map(|_| {
314 let (key, id) = choices[code % choices.len()];
315 code /= choices.len();
316 declaration(key, id)
317 })
318 .collect();
319 let mut ordered = input.clone();
320 crate::sort::sort_unstable_by(&mut ordered, |a, b| a.stable_key.cmp(&b.stable_key));
321 assert_eq!(
322 DeclarationSnapshot::canonicalize(input),
323 DeclarationSnapshot::new(ordered)
324 );
325 }
326 for count in [0, 1, 254, 255, 256] {
327 let input: Vec<_> = (0..count)
328 .rev()
329 .map(|index| {
330 declaration(
331 &format!("app.store{index:03}.v1"),
332 u8::try_from(index % 255).unwrap(),
333 )
334 })
335 .collect();
336 let result = DeclarationSnapshot::canonicalize(input);
337 if count <= 255 {
338 let snapshot = result.unwrap();
339 assert_eq!(snapshot.len(), count);
340 assert!(
341 snapshot
342 .declarations()
343 .windows(2)
344 .all(|pair| { pair[0].stable_key < pair[1].stable_key })
345 );
346 } else {
347 assert_eq!(result, Err(DeclarationSnapshotError::TooManyDeclarations));
348 }
349 }
350 }
351}