1use serde::{Deserialize, Serialize};
5use sha2::{Digest, Sha256};
6use std::collections::HashMap;
7
8pub use crate::core::Table;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct TableHashes {
14 pub table_hash: String,
16 pub header_hashes: HashMap<String, String>,
18 pub row_hashes: Option<Vec<String>>,
20}
21
22impl TableHashes {
23 pub fn compute(table: &Table) -> Self {
25 let mut header_hashes = HashMap::new();
26
27 for (idx, header) in table.headers.iter().enumerate() {
29 let column_data: Vec<&str> = table
30 .rows
31 .iter()
32 .map(|row| row.get(idx).map(|s| s.as_str()).unwrap_or(""))
33 .collect();
34
35 let hash = Self::hash_column(header, &column_data);
36 header_hashes.insert(header.clone(), hash);
37 }
38
39 let table_hash = Self::hash_table(&table.headers, &table.rows);
41
42 let row_hashes = Some(table.rows.iter().map(|row| Self::hash_row(row)).collect());
44
45 Self {
46 table_hash,
47 header_hashes,
48 row_hashes,
49 }
50 }
51
52 fn hash_column(header: &str, data: &[&str]) -> String {
54 let mut hasher = Sha256::new();
55 hasher.update(header.as_bytes());
56 for value in data {
57 hasher.update(value.as_bytes());
58 }
59 format!("{:x}", hasher.finalize())
60 }
61
62 fn hash_row(row: &[String]) -> String {
64 let mut hasher = Sha256::new();
65 for cell in row {
66 hasher.update(cell.as_bytes());
67 }
68 format!("{:x}", hasher.finalize())
69 }
70
71 fn hash_table(headers: &[String], rows: &[Vec<String>]) -> String {
73 let mut hasher = Sha256::new();
74
75 for h in headers {
77 hasher.update(h.as_bytes());
78 }
79
80 for row in rows {
82 for cell in row {
83 hasher.update(cell.as_bytes());
84 }
85 }
86
87 format!("{:x}", hasher.finalize())
88 }
89}