Skip to main content

prikk_object/payload/
common.rs

1//! Shared payload helper types.
2
3use prikk_error::Result;
4
5use crate::{CanonicalEncode, CanonicalWriter};
6
7/// A 32-byte Merkle root for a materialized tree state.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct MerkleRoot(pub [u8; 32]);
10
11/// A 32-byte digest over a canonicalized set of patch ids (RFC 115 Stage 1 design D4). Not
12/// persisted as its own object -- a pure comparison value, `MerkleRoot`'s own shape. Lives here
13/// rather than in `prikk-store` (where every value that *computes* one still does,
14/// `compute_patch_set_digest` and friends) because `TagPayload` (RFC 117 T1) carries one, and
15/// `prikk-object` cannot depend on `prikk-store` -- the same crate-boundary reason
16/// `state_root.rs`'s `compute_state_root` stays in `prikk-store` while `MerkleRoot` itself lives
17/// here.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct PatchSetDigest(pub [u8; 32]);
20
21/// Advisory patch intent.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23#[repr(u16)]
24pub enum Intent {
25    /// Feature work.
26    Feature = 1,
27    /// Bug fix.
28    Fix = 2,
29    /// Refactoring.
30    Refactor = 3,
31    /// Documentation.
32    Docs = 4,
33    /// Test-only change.
34    Test = 5,
35}
36
37impl Intent {
38    /// Stable numeric code.
39    #[must_use]
40    pub const fn code(self) -> u16 {
41        self as u16
42    }
43}
44
45/// Operation-level condition entry.
46#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
47pub struct OperationConditionEntry {
48    /// Condition key.
49    pub key: String,
50    /// Condition value.
51    pub value: OperationCondition,
52}
53
54impl CanonicalEncode for OperationConditionEntry {
55    fn encode_canonical(&self, writer: &mut CanonicalWriter) -> Result<()> {
56        writer.field_string(1, &self.key)?;
57        writer.field_record(2, &self.value)?;
58        Ok(())
59    }
60}
61
62/// Operation precondition.
63#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
64pub enum OperationCondition {
65    /// Old content hash must match before the operation applies.
66    OldContentHash(Vec<u8>),
67    /// Named anchor must exist.
68    AnchorExists(String),
69    /// Path must exist.
70    PathExists(String),
71    /// Path must be absent.
72    PathAbsent(String),
73}
74
75impl CanonicalEncode for OperationCondition {
76    fn encode_canonical(&self, writer: &mut CanonicalWriter) -> Result<()> {
77        match self {
78            Self::OldContentHash(hash) => {
79                writer.field_u32(1, 1)?;
80                writer.field_bytes(2, hash)?;
81            }
82            Self::AnchorExists(anchor) => {
83                writer.field_u32(1, 2)?;
84                writer.field_string(2, anchor)?;
85            }
86            Self::PathExists(path) => {
87                writer.field_u32(1, 3)?;
88                writer.field_string(2, path)?;
89            }
90            Self::PathAbsent(path) => {
91                writer.field_u32(1, 4)?;
92                writer.field_string(2, path)?;
93            }
94        }
95        Ok(())
96    }
97}