objects/object/
state_verification.rs1use std::collections::BTreeMap;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
10pub struct Verification {
11 pub tests_passed: Option<bool>,
13 pub tests_failed: Option<u32>,
15 pub coverage_pct: Option<f32>,
17 pub coverage_delta: Option<f32>,
19 pub lint_warnings: Option<u32>,
21 #[serde(default)]
23 pub custom: BTreeMap<String, serde_json::Value>,
24}
25
26impl Verification {
27 pub fn new() -> Self {
29 Self::default()
30 }
31
32 pub fn with_tests_passed(mut self, passed: bool) -> Self {
34 self.tests_passed = Some(passed);
35 self
36 }
37
38 pub fn with_tests_failed(mut self, failed: u32) -> Self {
40 self.tests_failed = Some(failed);
41 self
42 }
43
44 pub fn is_empty(&self) -> bool {
46 self.tests_passed.is_none()
47 && self.tests_failed.is_none()
48 && self.coverage_pct.is_none()
49 && self.coverage_delta.is_none()
50 && self.lint_warnings.is_none()
51 && self.custom.is_empty()
52 }
53
54 pub(crate) fn hash_len(&self) -> usize {
55 let mut len = 0;
56
57 len += 1 + self.tests_passed.map(|_| 1).unwrap_or(0);
58 len += 1 + self.tests_failed.map(|_| 4).unwrap_or(0);
59 len += 1 + self.coverage_pct.map(|_| 4).unwrap_or(0);
60 len += 1 + self.coverage_delta.map(|_| 4).unwrap_or(0);
61 len += 1 + self.lint_warnings.map(|_| 4).unwrap_or(0);
62
63 len += 4;
64 for (key, value) in &self.custom {
65 let value_bytes = serde_json::to_vec(value).unwrap_or_default();
66 len += 4 + key.len();
67 len += 4 + value_bytes.len();
68 }
69
70 len
71 }
72
73 pub(crate) fn update_hasher(&self, hasher: &mut blake3::Hasher) {
74 let tests_passed = self.tests_passed.map(u8::from);
75 write_optional_u8(hasher, tests_passed);
76 write_optional_u32(hasher, self.tests_failed);
77 write_optional_f32(hasher, self.coverage_pct);
78 write_optional_f32(hasher, self.coverage_delta);
79 write_optional_u32(hasher, self.lint_warnings);
80
81 let custom_len = self.custom.len() as u32;
82 hasher.update(&custom_len.to_le_bytes());
83 for (key, value) in &self.custom {
84 let key_bytes = key.as_bytes();
85 let value_bytes = serde_json::to_vec(value).unwrap_or_default();
86
87 hasher.update(&(key_bytes.len() as u32).to_le_bytes());
88 hasher.update(key_bytes);
89
90 hasher.update(&(value_bytes.len() as u32).to_le_bytes());
91 hasher.update(&value_bytes);
92 }
93 }
94}
95
96fn write_optional_u8(hasher: &mut blake3::Hasher, value: Option<u8>) {
97 match value {
98 Some(v) => {
99 hasher.update(&[1]);
100 hasher.update(&[v]);
101 }
102 None => {
103 hasher.update(&[0]);
104 }
105 }
106}
107
108fn write_optional_u32(hasher: &mut blake3::Hasher, value: Option<u32>) {
109 match value {
110 Some(v) => {
111 hasher.update(&[1]);
112 hasher.update(&v.to_le_bytes());
113 }
114 None => {
115 hasher.update(&[0]);
116 }
117 }
118}
119
120fn write_optional_f32(hasher: &mut blake3::Hasher, value: Option<f32>) {
121 match value {
122 Some(v) => {
123 hasher.update(&[1]);
124 hasher.update(&v.to_le_bytes());
125 }
126 None => {
127 hasher.update(&[0]);
128 }
129 }
130}