formualizer_eval/engine/
reference_fingerprint.rs1use formualizer_parse::parser::ReferenceType;
2use std::collections::hash_map::DefaultHasher;
3use std::hash::{Hash, Hasher};
4
5pub trait ReferenceFingerprint {
7 fn fingerprint(&self) -> String;
10}
11
12impl ReferenceFingerprint for ReferenceType {
13 fn fingerprint(&self) -> String {
14 match self {
17 ReferenceType::Cell { sheet, row, col } => {
18 format!("cell:{}:{}:{}", sheet.as_deref().unwrap_or("_"), row, col)
19 }
20 ReferenceType::Range {
21 sheet,
22 start_row,
23 start_col,
24 end_row,
25 end_col,
26 } => {
27 format!(
28 "range:{}:{}:{}:{}:{}",
29 sheet.as_deref().unwrap_or("_"),
30 start_row.map_or("*".to_string(), |r| r.to_string()),
31 start_col.map_or("*".to_string(), |c| c.to_string()),
32 end_row.map_or("*".to_string(), |r| r.to_string()),
33 end_col.map_or("*".to_string(), |c| c.to_string())
34 )
35 }
36 ReferenceType::Table(table_ref) => {
37 let mut hasher = DefaultHasher::new();
39 table_ref.hash(&mut hasher);
40 format!("table:{:x}", hasher.finish())
41 }
42 ReferenceType::NamedRange(name) => {
43 format!("named:{name}")
44 }
45 }
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn test_cell_fingerprint() {
55 let ref1 = ReferenceType::Cell {
56 sheet: None,
57 row: 5,
58 col: 10,
59 };
60
61 let ref2 = ReferenceType::Cell {
62 sheet: None,
63 row: 5,
64 col: 10,
65 };
66
67 assert_eq!(ref1.fingerprint(), ref2.fingerprint());
68 assert_eq!(ref1.fingerprint(), "cell:_:5:10");
69 }
70
71 #[test]
72 fn test_range_fingerprint() {
73 let ref1 = ReferenceType::Range {
74 sheet: Some("Sheet1".to_string()),
75 start_row: Some(0),
76 start_col: Some(0),
77 end_row: Some(99),
78 end_col: Some(0),
79 };
80
81 let ref2 = ReferenceType::Range {
82 sheet: Some("Sheet1".to_string()),
83 start_row: Some(0),
84 start_col: Some(0),
85 end_row: Some(99),
86 end_col: Some(0),
87 };
88
89 assert_eq!(ref1.fingerprint(), ref2.fingerprint());
90 assert_eq!(ref1.fingerprint(), "range:Sheet1:0:0:99:0");
91 }
92
93 #[test]
94 fn test_whole_column_fingerprint() {
95 let ref1 = ReferenceType::Range {
96 sheet: None,
97 start_row: None,
98 start_col: Some(0),
99 end_row: None,
100 end_col: Some(0),
101 };
102
103 assert_eq!(ref1.fingerprint(), "range:_:*:0:*:0");
104 }
105
106 #[test]
107 fn test_named_range_fingerprint() {
108 let ref1 = ReferenceType::NamedRange("MyRange".to_string());
109 let ref2 = ReferenceType::NamedRange("MyRange".to_string());
110
111 assert_eq!(ref1.fingerprint(), ref2.fingerprint());
112 assert_eq!(ref1.fingerprint(), "named:MyRange");
113 }
114
115 #[test]
116 fn test_different_refs_different_fingerprints() {
117 let ref1 = ReferenceType::Cell {
118 sheet: None,
119 row: 1,
120 col: 1,
121 };
122
123 let ref2 = ReferenceType::Cell {
124 sheet: None,
125 row: 1,
126 col: 2,
127 };
128
129 assert_ne!(ref1.fingerprint(), ref2.fingerprint());
130 }
131}