wenlan_types/
lint_coverage.rs1use 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}