1use appcore_contracts::{ProviderConfig, ProviderId};
14use std::collections::{BTreeMap, BTreeSet};
15
16pub const STORAGE_CAPABILITY_DESCRIPTOR_VERSION_V1: u16 = 1;
18pub const STORAGE_REQUIRED_CAPABILITIES_SETTING: &str = "required_capabilities";
20pub const STORAGE_CAPABILITY_COUNT_V1: usize = 7;
22pub const MAX_STORAGE_CAPABILITY_PROVIDERS_V1: usize = 32;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
27pub enum StorageCapabilityV1 {
28 Transactions,
30 Locking,
32 Snapshot,
34 Streaming,
36 OnlineBackup,
38 MultiProcess,
40 MultiHost,
42}
43
44impl StorageCapabilityV1 {
45 pub const fn as_str(self) -> &'static str {
47 match self {
48 Self::Transactions => "transactions",
49 Self::Locking => "locking",
50 Self::Snapshot => "snapshot",
51 Self::Streaming => "streaming",
52 Self::OnlineBackup => "online_backup",
53 Self::MultiProcess => "multi_process",
54 Self::MultiHost => "multi_host",
55 }
56 }
57
58 fn parse(value: &str) -> Result<Self, StorageCapabilityError> {
59 match value {
60 "transactions" => Ok(Self::Transactions),
61 "locking" => Ok(Self::Locking),
62 "snapshot" => Ok(Self::Snapshot),
63 "streaming" => Ok(Self::Streaming),
64 "online_backup" => Ok(Self::OnlineBackup),
65 "multi_process" => Ok(Self::MultiProcess),
66 "multi_host" => Ok(Self::MultiHost),
67 _ => Err(StorageCapabilityError::UnknownRequirement),
68 }
69 }
70}
71
72impl std::fmt::Display for StorageCapabilityV1 {
73 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 formatter.write_str(self.as_str())
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq)]
80pub enum StorageCapabilityError {
81 InvalidDescriptor,
83 UnknownRequirement,
85 DuplicateRequirement(StorageCapabilityV1),
87 CatalogFull,
89 DuplicateProvider(ProviderId),
91 ProviderUnavailable(ProviderId),
93 MissingCapability {
95 provider_id: ProviderId,
97 capability: StorageCapabilityV1,
99 },
100}
101
102impl std::fmt::Display for StorageCapabilityError {
103 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 match self {
105 Self::InvalidDescriptor => {
106 formatter.write_str("storage capability descriptor identity is invalid")
107 }
108 Self::UnknownRequirement => {
109 formatter.write_str("storage capability requirement is unknown")
110 }
111 Self::DuplicateRequirement(capability) => write!(
112 formatter,
113 "storage capability requirement is duplicated: {capability}"
114 ),
115 Self::CatalogFull => formatter.write_str("storage capability provider catalog is full"),
116 Self::DuplicateProvider(provider_id) => write!(
117 formatter,
118 "storage capability descriptor is duplicated for provider: {provider_id}"
119 ),
120 Self::ProviderUnavailable(provider_id) => write!(
121 formatter,
122 "storage capability descriptor is unavailable for provider: {provider_id}"
123 ),
124 Self::MissingCapability {
125 provider_id,
126 capability,
127 } => write!(
128 formatter,
129 "storage provider {provider_id} does not support required capability {capability}"
130 ),
131 }
132 }
133}
134
135impl std::error::Error for StorageCapabilityError {}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct StorageCapabilityDescriptorV1 {
140 provider_id: ProviderId,
141 capabilities: BTreeSet<StorageCapabilityV1>,
142}
143
144impl StorageCapabilityDescriptorV1 {
145 pub fn new(
147 provider_id: ProviderId,
148 capabilities: impl IntoIterator<Item = StorageCapabilityV1>,
149 ) -> Self {
150 Self {
151 provider_id,
152 capabilities: capabilities.into_iter().collect(),
153 }
154 }
155
156 pub const fn descriptor_version(&self) -> u16 {
158 STORAGE_CAPABILITY_DESCRIPTOR_VERSION_V1
159 }
160
161 pub fn provider_id(&self) -> &ProviderId {
163 &self.provider_id
164 }
165
166 pub fn capabilities(&self) -> &BTreeSet<StorageCapabilityV1> {
168 &self.capabilities
169 }
170
171 pub fn supports(&self, capability: StorageCapabilityV1) -> bool {
173 self.capabilities.contains(&capability)
174 }
175
176 pub fn validate(
178 &self,
179 requirements: &StorageCapabilityRequirementsV1,
180 ) -> Result<(), StorageCapabilityError> {
181 for capability in requirements.capabilities() {
182 if !self.supports(*capability) {
183 return Err(StorageCapabilityError::MissingCapability {
184 provider_id: self.provider_id.clone(),
185 capability: *capability,
186 });
187 }
188 }
189 Ok(())
190 }
191}
192
193#[derive(Debug, Clone, Default, PartialEq, Eq)]
195pub struct StorageCapabilityRequirementsV1 {
196 capabilities: BTreeSet<StorageCapabilityV1>,
197}
198
199impl StorageCapabilityRequirementsV1 {
200 pub fn new() -> Self {
202 Self::default()
203 }
204
205 pub fn from_provider_config(config: &ProviderConfig) -> Result<Self, StorageCapabilityError> {
207 let Some(value) = config.settings().get(STORAGE_REQUIRED_CAPABILITIES_SETTING) else {
208 return Ok(Self::new());
209 };
210 let mut requirements = Self::new();
211 if value.trim().is_empty() {
212 return Err(StorageCapabilityError::UnknownRequirement);
213 }
214 for raw in value.split(',') {
215 let capability = StorageCapabilityV1::parse(raw.trim())?;
216 requirements.require(capability)?;
217 }
218 Ok(requirements)
219 }
220
221 pub fn require(
223 &mut self,
224 capability: StorageCapabilityV1,
225 ) -> Result<(), StorageCapabilityError> {
226 if !self.capabilities.insert(capability) {
227 return Err(StorageCapabilityError::DuplicateRequirement(capability));
228 }
229 Ok(())
230 }
231
232 pub fn include(&mut self, capability: StorageCapabilityV1) {
234 self.capabilities.insert(capability);
235 }
236
237 pub fn capabilities(&self) -> &BTreeSet<StorageCapabilityV1> {
239 &self.capabilities
240 }
241}
242
243pub trait StorageCapabilityProviderV1 {
245 fn storage_capabilities_v1(
247 &self,
248 ) -> Result<StorageCapabilityDescriptorV1, StorageCapabilityError>;
249}
250
251#[derive(Debug, Clone, Default)]
253pub struct StorageCapabilityCatalogV1 {
254 descriptors: BTreeMap<ProviderId, StorageCapabilityDescriptorV1>,
255}
256
257impl StorageCapabilityCatalogV1 {
258 pub fn new() -> Self {
260 Self::default()
261 }
262
263 pub fn register(
265 &mut self,
266 descriptor: StorageCapabilityDescriptorV1,
267 ) -> Result<(), StorageCapabilityError> {
268 if self.descriptors.contains_key(descriptor.provider_id()) {
269 return Err(StorageCapabilityError::DuplicateProvider(
270 descriptor.provider_id().clone(),
271 ));
272 }
273 if self.descriptors.len() >= MAX_STORAGE_CAPABILITY_PROVIDERS_V1 {
274 return Err(StorageCapabilityError::CatalogFull);
275 }
276 self.descriptors
277 .insert(descriptor.provider_id().clone(), descriptor);
278 Ok(())
279 }
280
281 pub fn validate(
283 &self,
284 provider_id: &ProviderId,
285 requirements: &StorageCapabilityRequirementsV1,
286 ) -> Result<(), StorageCapabilityError> {
287 self.descriptors
288 .get(provider_id)
289 .ok_or_else(|| StorageCapabilityError::ProviderUnavailable(provider_id.clone()))?
290 .validate(requirements)
291 }
292}