Skip to main content

weavatrix_memory/domain/
evidence.rs

1use crate::error::{MemoryError, Result};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
5#[serde(transparent)]
6pub struct Confidence(u16);
7
8impl Confidence {
9    pub const CERTAIN: Self = Self(10_000);
10
11    /// Creates confidence measured in basis points from 0 through 10,000.
12    ///
13    /// # Errors
14    ///
15    /// Rejects values above 10,000.
16    pub fn from_basis_points(value: u16) -> Result<Self> {
17        if value > 10_000 {
18            return Err(MemoryError::InvalidValue {
19                field: "confidence",
20                reason: "must be between 0 and 10,000 basis points",
21            });
22        }
23        Ok(Self(value))
24    }
25
26    #[must_use]
27    pub const fn basis_points(self) -> u16 {
28        self.0
29    }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub struct Evidence {
34    pub kind: String,
35    pub source: String,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub locator: Option<String>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub digest: Option<String>,
40}
41
42impl Evidence {
43    /// Creates a provenance record.
44    ///
45    /// # Errors
46    ///
47    /// Rejects empty or whitespace-padded kind and source values.
48    pub fn new(kind: impl Into<String>, source: impl Into<String>) -> Result<Self> {
49        let evidence = Self {
50            kind: kind.into(),
51            source: source.into(),
52            locator: None,
53            digest: None,
54        };
55        evidence.validate()?;
56        Ok(evidence)
57    }
58
59    #[must_use]
60    pub fn with_locator(mut self, locator: impl Into<String>) -> Self {
61        self.locator = Some(locator.into());
62        self
63    }
64
65    #[must_use]
66    pub fn with_digest(mut self, digest: impl Into<String>) -> Self {
67        self.digest = Some(digest.into());
68        self
69    }
70
71    pub(crate) fn validate(&self) -> Result<()> {
72        super::validate_text("evidence.kind", &self.kind)?;
73        super::validate_text("evidence.source", &self.source)?;
74        super::validate_optional_text("evidence.locator", self.locator.as_deref())?;
75        super::validate_optional_text("evidence.digest", self.digest.as_deref())
76    }
77}