Skip to main content

wenlan_types/
lint_coverage.rs

1// SPDX-License-Identifier: Apache-2.0
2use super::contract::{LintContractError, LINT_MAX_EVIDENCE_PER_CHECK};
3use serde::{de::Error as _, Deserialize, Deserializer, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "snake_case")]
7pub enum LintValidationMethod {
8    ExactAggregate,
9    FullEnumeration,
10    IntrinsicSample,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
14pub struct LintCoverage {
15    method: LintValidationMethod,
16    authorized_denominator: u64,
17    evaluated: u64,
18    evidence_cap: u16,
19    truncated: bool,
20    evidence_returned: u64,
21}
22
23#[derive(Deserialize)]
24struct LintCoverageWire {
25    method: LintValidationMethod,
26    authorized_denominator: u64,
27    evaluated: u64,
28    evidence_cap: u16,
29    truncated: bool,
30    evidence_returned: u64,
31}
32
33impl LintCoverage {
34    pub fn new(
35        method: LintValidationMethod,
36        authorized_denominator: u64,
37        evaluated: u64,
38        evidence_cap: u16,
39        truncated: bool,
40        evidence_returned: u64,
41    ) -> Result<Self, LintContractError> {
42        let coverage = Self {
43            method,
44            authorized_denominator,
45            evaluated,
46            evidence_cap,
47            truncated,
48            evidence_returned,
49        };
50        coverage.validate(
51            usize::try_from(evidence_returned).map_err(|_| LintContractError::InvalidCoverage)?,
52        )?;
53        Ok(coverage)
54    }
55
56    pub(crate) fn validate(&self, evidence_count: usize) -> Result<(), LintContractError> {
57        let evidence_count =
58            u64::try_from(evidence_count).map_err(|_| LintContractError::InvalidCoverage)?;
59        let covers_authorized_population = match self.method {
60            LintValidationMethod::FullEnumeration => self.evaluated == self.authorized_denominator,
61            LintValidationMethod::ExactAggregate | LintValidationMethod::IntrinsicSample => true,
62        };
63        if !covers_authorized_population
64            || self.evaluated > self.authorized_denominator
65            || self.evidence_cap != LINT_MAX_EVIDENCE_PER_CHECK
66            || self.evidence_returned != evidence_count
67            || evidence_count > u64::from(self.evidence_cap)
68        {
69            Err(LintContractError::InvalidCoverage)
70        } else {
71            Ok(())
72        }
73    }
74
75    pub(crate) const fn authorized_denominator(&self) -> u64 {
76        self.authorized_denominator
77    }
78
79    pub const fn method(&self) -> LintValidationMethod {
80        self.method
81    }
82
83    pub const fn denominator(&self) -> u64 {
84        self.authorized_denominator
85    }
86
87    pub const fn evaluated(&self) -> u64 {
88        self.evaluated
89    }
90
91    pub const fn evidence_cap(&self) -> u16 {
92        self.evidence_cap
93    }
94
95    pub const fn truncated(&self) -> bool {
96        self.truncated
97    }
98
99    pub const fn evidence_returned(&self) -> u64 {
100        self.evidence_returned
101    }
102}
103
104impl<'de> Deserialize<'de> for LintCoverage {
105    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
106    where
107        D: Deserializer<'de>,
108    {
109        let wire = LintCoverageWire::deserialize(deserializer)?;
110        Self::new(
111            wire.method,
112            wire.authorized_denominator,
113            wire.evaluated,
114            wire.evidence_cap,
115            wire.truncated,
116            wire.evidence_returned,
117        )
118        .map_err(D::Error::custom)
119    }
120}