appcore_contracts/policy/
capability.rs1use super::*;
12
13#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "snake_case")]
16pub enum CapabilityClass {
17 Infrastructure,
19 #[default]
21 Functional,
22}
23
24impl CapabilityClass {
25 fn is_functional(&self) -> bool {
26 *self == Self::Functional
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum CapabilityVisibility {
34 Local,
36 Cluster,
38 Tenant,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44pub struct CapabilityDeclaration {
45 id: CapabilityId,
46 #[serde(default, skip_serializing_if = "CapabilityClass::is_functional")]
47 class: CapabilityClass,
48 version: String,
49 mode: CapabilityMode,
50 visibility: CapabilityVisibility,
51 requires_leader: bool,
52 idempotency_required: bool,
53}
54
55impl CapabilityDeclaration {
56 pub fn new(
58 id: CapabilityId,
59 version: impl Into<String>,
60 mode: CapabilityMode,
61 visibility: CapabilityVisibility,
62 ) -> ContractResult<Self> {
63 let declaration = Self {
64 id,
65 class: CapabilityClass::Functional,
66 version: version.into(),
67 mode,
68 visibility,
69 requires_leader: false,
70 idempotency_required: false,
71 };
72 declaration.validate()?;
73 Ok(declaration)
74 }
75
76 pub fn with_class(mut self, class: CapabilityClass) -> Self {
78 self.class = class;
79 self
80 }
81
82 pub fn with_leadership(mut self, required: bool) -> Self {
84 self.requires_leader = required;
85 self
86 }
87
88 pub fn with_idempotency(mut self, required: bool) -> Self {
90 self.idempotency_required = required;
91 self
92 }
93
94 pub fn id(&self) -> &CapabilityId {
96 &self.id
97 }
98
99 pub fn class(&self) -> CapabilityClass {
101 self.class
102 }
103
104 pub fn version(&self) -> &str {
106 &self.version
107 }
108
109 pub fn mode(&self) -> CapabilityMode {
111 self.mode
112 }
113
114 pub fn visibility(&self) -> CapabilityVisibility {
116 self.visibility
117 }
118
119 pub fn requires_leader(&self) -> bool {
121 self.requires_leader
122 }
123
124 pub fn idempotency_required(&self) -> bool {
126 self.idempotency_required
127 }
128
129 pub(crate) fn validate(&self) -> ContractResult<()> {
130 validate_text("capability.version", &self.version, 64)
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
136pub struct RuntimeRequirements {
137 minimum_runtime_version: String,
138 maximum_runtime_version: Option<String>,
139 protocol_version: String,
140 required_features: BTreeSet<FeatureId>,
141}
142
143impl RuntimeRequirements {
144 pub fn new(
146 minimum_runtime_version: impl Into<String>,
147 protocol_version: impl Into<String>,
148 ) -> ContractResult<Self> {
149 let requirements = Self {
150 minimum_runtime_version: minimum_runtime_version.into(),
151 maximum_runtime_version: None,
152 protocol_version: protocol_version.into(),
153 required_features: BTreeSet::new(),
154 };
155 requirements.validate()?;
156 Ok(requirements)
157 }
158
159 pub fn with_maximum_runtime_version(
161 mut self,
162 version: impl Into<String>,
163 ) -> ContractResult<Self> {
164 let version = version.into();
165 validate_text("runtime.maximum_version", &version, 64)?;
166 self.maximum_runtime_version = Some(version);
167 Ok(self)
168 }
169
170 pub fn with_required_feature(mut self, feature: FeatureId) -> Self {
172 self.required_features.insert(feature);
173 self
174 }
175
176 pub fn minimum_runtime_version(&self) -> &str {
178 &self.minimum_runtime_version
179 }
180
181 pub fn maximum_runtime_version(&self) -> Option<&str> {
183 self.maximum_runtime_version.as_deref()
184 }
185
186 pub fn protocol_version(&self) -> &str {
188 &self.protocol_version
189 }
190
191 pub fn required_features(&self) -> &BTreeSet<FeatureId> {
193 &self.required_features
194 }
195
196 pub(crate) fn validate(&self) -> ContractResult<()> {
197 validate_text("runtime.minimum_version", &self.minimum_runtime_version, 64)?;
198 validate_text("runtime.protocol_version", &self.protocol_version, 64)?;
199 if let Some(version) = &self.maximum_runtime_version {
200 validate_text("runtime.maximum_version", version, 64)?;
201 }
202 Ok(())
203 }
204}