Skip to main content

bcx_model/
statement.rs

1use crate::{AdmissionResult, EffectResult, OperationAction};
2use bcx_core::{CapabilityRef, CheckpointId, PolicyId, StatementId, SubjectId, ValidationError};
3
4/// BCX statement body kind.
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub enum StatementKind {
7    /// A participant declares intended meaning before execution.
8    Intent,
9    /// A policy, runtime, or authority records an admission decision.
10    Admission,
11    /// A participant records the effect of an attempted operation.
12    Effect,
13    /// Authority or responsibility is delegated.
14    Delegation,
15    /// A prior statement, authority, or delegation is revoked.
16    Revocation,
17    /// A graph, state, or settlement checkpoint is recorded.
18    Checkpoint,
19    /// A statement contradicts another statement.
20    Contradiction,
21}
22
23/// Declared intent before execution.
24#[derive(Debug, Eq, PartialEq)]
25pub struct Intent {
26    statement_id: StatementId,
27    subject: SubjectId,
28    action: OperationAction,
29}
30
31impl Intent {
32    /// Creates an intent body from required fields.
33    #[must_use]
34    pub const fn new(
35        statement_id: StatementId,
36        subject: SubjectId,
37        action: OperationAction,
38    ) -> Self {
39        Self {
40            statement_id,
41            subject,
42            action,
43        }
44    }
45
46    /// Returns this body kind.
47    #[must_use]
48    pub const fn kind(&self) -> StatementKind {
49        StatementKind::Intent
50    }
51
52    /// Returns the statement identifier.
53    #[must_use]
54    pub const fn statement_id(&self) -> &StatementId {
55        &self.statement_id
56    }
57
58    /// Returns the subject identifier.
59    #[must_use]
60    pub const fn subject(&self) -> &SubjectId {
61        &self.subject
62    }
63
64    /// Returns the requested action.
65    #[must_use]
66    pub const fn action(&self) -> OperationAction {
67        self.action
68    }
69}
70
71/// Admission decision for a prior intent.
72#[derive(Debug, Eq, PartialEq)]
73pub struct Admission {
74    statement_id: StatementId,
75    intent_id: StatementId,
76    policy_id: PolicyId,
77    result: AdmissionResult,
78}
79
80impl Admission {
81    /// Creates an admission body from required fields.
82    pub fn new(
83        statement_id: StatementId,
84        intent_id: StatementId,
85        policy_id: PolicyId,
86        result: AdmissionResult,
87    ) -> Result<Self, ValidationError> {
88        ensure_distinct(&statement_id, &intent_id)?;
89        Ok(Self {
90            statement_id,
91            intent_id,
92            policy_id,
93            result,
94        })
95    }
96
97    /// Returns this body kind.
98    #[must_use]
99    pub const fn kind(&self) -> StatementKind {
100        StatementKind::Admission
101    }
102
103    /// Returns the admission statement identifier.
104    #[must_use]
105    pub const fn statement_id(&self) -> &StatementId {
106        &self.statement_id
107    }
108
109    /// Returns the admitted intent identifier.
110    #[must_use]
111    pub const fn intent_id(&self) -> &StatementId {
112        &self.intent_id
113    }
114
115    /// Returns the policy identifier used for the decision.
116    #[must_use]
117    pub const fn policy_id(&self) -> &PolicyId {
118        &self.policy_id
119    }
120
121    /// Returns the admission result.
122    #[must_use]
123    pub const fn result(&self) -> AdmissionResult {
124        self.result
125    }
126}
127
128/// Recorded effect for a prior intent.
129#[derive(Debug, Eq, PartialEq)]
130pub struct Effect {
131    statement_id: StatementId,
132    intent_id: StatementId,
133    result: EffectResult,
134}
135
136impl Effect {
137    /// Creates an effect body from required fields.
138    pub fn new(
139        statement_id: StatementId,
140        intent_id: StatementId,
141        result: EffectResult,
142    ) -> Result<Self, ValidationError> {
143        ensure_distinct(&statement_id, &intent_id)?;
144        Ok(Self {
145            statement_id,
146            intent_id,
147            result,
148        })
149    }
150
151    /// Returns this body kind.
152    #[must_use]
153    pub const fn kind(&self) -> StatementKind {
154        StatementKind::Effect
155    }
156
157    /// Returns the effect statement identifier.
158    #[must_use]
159    pub const fn statement_id(&self) -> &StatementId {
160        &self.statement_id
161    }
162
163    /// Returns the originating intent identifier.
164    #[must_use]
165    pub const fn intent_id(&self) -> &StatementId {
166        &self.intent_id
167    }
168
169    /// Returns the effect result.
170    #[must_use]
171    pub const fn result(&self) -> EffectResult {
172        self.result
173    }
174}
175
176/// Delegation from one subject to another under a capability reference.
177#[derive(Debug, Eq, PartialEq)]
178pub struct Delegation {
179    statement_id: StatementId,
180    from_subject: SubjectId,
181    to_subject: SubjectId,
182    capability: CapabilityRef,
183}
184
185impl Delegation {
186    /// Creates a delegation body from required fields.
187    pub fn new(
188        statement_id: StatementId,
189        from_subject: SubjectId,
190        to_subject: SubjectId,
191        capability: CapabilityRef,
192    ) -> Result<Self, ValidationError> {
193        if from_subject == to_subject {
194            return Err(ValidationError::Malformed);
195        }
196        Ok(Self {
197            statement_id,
198            from_subject,
199            to_subject,
200            capability,
201        })
202    }
203
204    /// Returns this body kind.
205    #[must_use]
206    pub const fn kind(&self) -> StatementKind {
207        StatementKind::Delegation
208    }
209
210    /// Returns the delegation statement identifier.
211    #[must_use]
212    pub const fn statement_id(&self) -> &StatementId {
213        &self.statement_id
214    }
215
216    /// Returns the delegating subject.
217    #[must_use]
218    pub const fn from_subject(&self) -> &SubjectId {
219        &self.from_subject
220    }
221
222    /// Returns the delegated subject.
223    #[must_use]
224    pub const fn to_subject(&self) -> &SubjectId {
225        &self.to_subject
226    }
227
228    /// Returns the delegated capability reference.
229    #[must_use]
230    pub const fn capability(&self) -> CapabilityRef {
231        self.capability
232    }
233}
234
235/// Revocation of a prior statement by an authority.
236#[derive(Debug, Eq, PartialEq)]
237pub struct Revocation {
238    statement_id: StatementId,
239    target_id: StatementId,
240    authority: CapabilityRef,
241}
242
243impl Revocation {
244    /// Creates a revocation body from required fields.
245    pub fn new(
246        statement_id: StatementId,
247        target_id: StatementId,
248        authority: CapabilityRef,
249    ) -> Result<Self, ValidationError> {
250        ensure_distinct(&statement_id, &target_id)?;
251        Ok(Self {
252            statement_id,
253            target_id,
254            authority,
255        })
256    }
257
258    /// Returns this body kind.
259    #[must_use]
260    pub const fn kind(&self) -> StatementKind {
261        StatementKind::Revocation
262    }
263
264    /// Returns the revocation statement identifier.
265    #[must_use]
266    pub const fn statement_id(&self) -> &StatementId {
267        &self.statement_id
268    }
269
270    /// Returns the revoked statement identifier.
271    #[must_use]
272    pub const fn target_id(&self) -> &StatementId {
273        &self.target_id
274    }
275
276    /// Returns the revoking authority reference.
277    #[must_use]
278    pub const fn authority(&self) -> CapabilityRef {
279        self.authority
280    }
281}
282
283/// Checkpoint statement for committed graph, state, or settlement evidence.
284#[derive(Debug, Eq, PartialEq)]
285pub struct Checkpoint {
286    statement_id: StatementId,
287    checkpoint_id: CheckpointId,
288    subject: SubjectId,
289}
290
291impl Checkpoint {
292    /// Creates a checkpoint body from required fields.
293    #[must_use]
294    pub const fn new(
295        statement_id: StatementId,
296        checkpoint_id: CheckpointId,
297        subject: SubjectId,
298    ) -> Self {
299        Self {
300            statement_id,
301            checkpoint_id,
302            subject,
303        }
304    }
305
306    /// Returns this body kind.
307    #[must_use]
308    pub const fn kind(&self) -> StatementKind {
309        StatementKind::Checkpoint
310    }
311
312    /// Returns the checkpoint statement identifier.
313    #[must_use]
314    pub const fn statement_id(&self) -> &StatementId {
315        &self.statement_id
316    }
317
318    /// Returns the checkpoint identifier.
319    #[must_use]
320    pub const fn checkpoint_id(&self) -> &CheckpointId {
321        &self.checkpoint_id
322    }
323
324    /// Returns the checkpoint subject.
325    #[must_use]
326    pub const fn subject(&self) -> &SubjectId {
327        &self.subject
328    }
329}
330
331/// Contradiction between two distinct statements.
332#[derive(Debug, Eq, PartialEq)]
333pub struct Contradiction {
334    statement_id: StatementId,
335    disputed_id: StatementId,
336    contradicts_id: StatementId,
337}
338
339impl Contradiction {
340    /// Creates a contradiction body from required fields.
341    pub fn new(
342        statement_id: StatementId,
343        disputed_id: StatementId,
344        contradicts_id: StatementId,
345    ) -> Result<Self, ValidationError> {
346        ensure_distinct(&statement_id, &disputed_id)?;
347        ensure_distinct(&statement_id, &contradicts_id)?;
348        ensure_distinct(&disputed_id, &contradicts_id)?;
349        Ok(Self {
350            statement_id,
351            disputed_id,
352            contradicts_id,
353        })
354    }
355
356    /// Returns this body kind.
357    #[must_use]
358    pub const fn kind(&self) -> StatementKind {
359        StatementKind::Contradiction
360    }
361
362    /// Returns the contradiction statement identifier.
363    #[must_use]
364    pub const fn statement_id(&self) -> &StatementId {
365        &self.statement_id
366    }
367
368    /// Returns the disputed statement identifier.
369    #[must_use]
370    pub const fn disputed_id(&self) -> &StatementId {
371        &self.disputed_id
372    }
373
374    /// Returns the contradicting statement identifier.
375    #[must_use]
376    pub const fn contradicts_id(&self) -> &StatementId {
377        &self.contradicts_id
378    }
379}
380
381fn ensure_distinct(left: &StatementId, right: &StatementId) -> Result<(), ValidationError> {
382    if left == right {
383        Err(ValidationError::Malformed)
384    } else {
385        Ok(())
386    }
387}