1use crate::{
2 key::{StableKey, StableKeyError},
3 slot::{MemoryManagerSlot, MemoryManagerSlotError},
4};
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
19#[serde(deny_unknown_fields)]
20pub struct AllocationDeclaration {
21 pub(crate) stable_key: StableKey,
23 pub(crate) slot: MemoryManagerSlot,
25}
26
27impl AllocationDeclaration {
28 pub fn new(
30 stable_key: impl AsRef<str>,
31 slot: MemoryManagerSlot,
32 ) -> Result<Self, DeclarationSnapshotError> {
33 let stable_key = StableKey::parse(stable_key).map_err(DeclarationSnapshotError::Key)?;
34 Ok(Self { stable_key, slot })
35 }
36
37 pub fn memory_manager(
39 stable_key: impl AsRef<str>,
40 id: u8,
41 ) -> Result<Self, DeclarationSnapshotError> {
42 let slot =
43 MemoryManagerSlot::new(id).map_err(DeclarationSnapshotError::MemoryManagerSlot)?;
44 Self::new(stable_key, slot)
45 }
46
47 #[must_use]
49 pub const fn stable_key(&self) -> &StableKey {
50 &self.stable_key
51 }
52
53 #[must_use]
55 pub const fn slot(&self) -> &MemoryManagerSlot {
56 &self.slot
57 }
58}
59
60#[non_exhaustive]
67#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
68pub enum DeclarationSnapshotError {
69 #[error(transparent)]
71 Key(StableKeyError),
72 #[error(transparent)]
74 MemoryManagerSlot(MemoryManagerSlotError),
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::slot::MemoryManagerSlot;
81
82 fn declaration(key: &str, id: u8) -> AllocationDeclaration {
83 AllocationDeclaration::new(key, MemoryManagerSlot::new(id).expect("usable slot"))
84 .expect("declaration")
85 }
86
87 #[test]
88 fn memory_manager_declaration_constructor_builds_common_declaration() {
89 let declaration =
90 AllocationDeclaration::memory_manager("app.orders.v1", 100).expect("declaration");
91
92 assert_eq!(declaration.stable_key.as_str(), "app.orders.v1");
93 assert_eq!(
94 declaration.slot,
95 MemoryManagerSlot::new(100).expect("usable slot")
96 );
97 }
98
99 #[test]
100 fn memory_manager_declaration_constructor_rejects_invalid_slot() {
101 let err = AllocationDeclaration::memory_manager("app.orders.v1", u8::MAX)
102 .expect_err("sentinel must fail");
103
104 assert!(matches!(
105 err,
106 DeclarationSnapshotError::MemoryManagerSlot(_)
107 ));
108 }
109
110 #[test]
111 fn declaration_decode_rejects_unusable_memory_manager_slot() {
112 let mut value = serde_json::to_value(declaration("app.orders.v1", 100)).unwrap();
113 value["slot"] = serde_json::json!(255);
114 assert!(serde_json::from_value::<AllocationDeclaration>(value.clone()).is_err());
115 let bytes = crate::test_cbor::to_vec(&value).unwrap();
116 assert!(crate::test_cbor::from_slice::<AllocationDeclaration>(&bytes).is_err());
117 }
118}