haystack_core/kinds/
ref_.rs1use std::fmt;
4use std::hash::{Hash, Hasher};
5
6#[derive(Debug, Clone)]
13pub struct HRef {
14 pub val: String,
15 pub dis: Option<String>,
16}
17
18impl HRef {
19 pub fn new(val: impl Into<String>, dis: Option<String>) -> Self {
20 Self {
21 val: val.into(),
22 dis,
23 }
24 }
25
26 pub fn from_val(val: impl Into<String>) -> Self {
27 Self {
28 val: val.into(),
29 dis: None,
30 }
31 }
32}
33
34impl PartialEq for HRef {
35 fn eq(&self, other: &Self) -> bool {
36 self.val == other.val
37 }
38}
39
40impl Eq for HRef {}
41
42impl Hash for HRef {
43 fn hash<H: Hasher>(&self, state: &mut H) {
44 self.val.hash(state);
45 }
46}
47
48impl fmt::Display for HRef {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "@{}", self.val)?;
51 if let Some(ref dis) = self.dis {
52 write!(f, " '{dis}'")?;
53 }
54 Ok(())
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use std::collections::HashSet;
62
63 #[test]
64 fn ref_display_without_dis() {
65 let r = HRef::from_val("site-1");
66 assert_eq!(r.to_string(), "@site-1");
67 }
68
69 #[test]
70 fn ref_display_with_dis() {
71 let r = HRef::new("site-1", Some("Main Site".into()));
72 assert_eq!(r.to_string(), "@site-1 'Main Site'");
73 }
74
75 #[test]
76 fn ref_equality_ignores_dis() {
77 let a = HRef::new("site-1", Some("Building A".into()));
78 let b = HRef::new("site-1", Some("Different Name".into()));
79 let c = HRef::from_val("site-1");
80 assert_eq!(a, b);
81 assert_eq!(a, c);
82 }
83
84 #[test]
85 fn ref_hash_ignores_dis() {
86 let a = HRef::new("site-1", Some("A".into()));
87 let b = HRef::new("site-1", Some("B".into()));
88 let mut set = HashSet::new();
89 set.insert(a);
90 assert!(set.contains(&b));
91 }
92
93 #[test]
94 fn ref_inequality() {
95 let a = HRef::from_val("site-1");
96 let b = HRef::from_val("site-2");
97 assert_ne!(a, b);
98 }
99
100 #[test]
101 fn ref_from_val_convenience() {
102 let r = HRef::from_val("abc");
103 assert_eq!(r.val, "abc");
104 assert_eq!(r.dis, None);
105 }
106}