msg_tool\utils/
case_insensitive_string.rs1use serde::Deserialize;
2use std::borrow::Borrow;
3use std::cmp::Ordering;
4use std::hash::{Hash, Hasher};
5use std::ops::{Deref, DerefMut};
6
7#[derive(Debug, Deserialize)]
8#[serde(transparent)]
9pub struct CaseInsensitiveString(String);
13
14impl PartialEq for CaseInsensitiveString {
15 fn eq(&self, other: &Self) -> bool {
16 self.0.eq_ignore_ascii_case(&other.0)
17 }
18}
19
20impl PartialEq<String> for CaseInsensitiveString {
21 fn eq(&self, other: &String) -> bool {
22 self.0.eq_ignore_ascii_case(other)
23 }
24}
25
26impl PartialEq<&str> for CaseInsensitiveString {
27 fn eq(&self, other: &&str) -> bool {
28 self.0.eq_ignore_ascii_case(other)
29 }
30}
31
32impl Eq for CaseInsensitiveString {}
33
34impl PartialOrd for CaseInsensitiveString {
35 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
36 Some(self.cmp(other))
37 }
38}
39
40impl Ord for CaseInsensitiveString {
41 fn cmp(&self, other: &Self) -> Ordering {
42 self.0
43 .to_ascii_lowercase()
44 .cmp(&other.0.to_ascii_lowercase())
45 }
46}
47
48impl Deref for CaseInsensitiveString {
49 type Target = String;
50 fn deref(&self) -> &Self::Target {
51 &self.0
52 }
53}
54
55impl DerefMut for CaseInsensitiveString {
56 fn deref_mut(&mut self) -> &mut Self::Target {
57 &mut self.0
58 }
59}
60
61impl std::fmt::Display for CaseInsensitiveString {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 self.0.fmt(f)
64 }
65}
66
67impl Hash for CaseInsensitiveString {
68 fn hash<H: Hasher>(&self, state: &mut H) {
69 self.0.to_ascii_lowercase().hash(state);
70 }
71}
72
73impl Borrow<CaseInsensitiveStr> for CaseInsensitiveString {
74 fn borrow(&self) -> &CaseInsensitiveStr {
75 CaseInsensitiveStr::from_str(&self.0)
76 }
77}
78
79#[repr(transparent)]
80pub struct CaseInsensitiveStr(str);
81
82impl CaseInsensitiveStr {
83 pub fn from_str(s: &str) -> &Self {
84 unsafe { &*(s as *const str as *const Self) }
86 }
87
88 pub fn as_str(&self) -> &str {
89 &self.0
90 }
91}
92
93impl PartialEq for CaseInsensitiveStr {
94 fn eq(&self, other: &Self) -> bool {
95 self.eq_ignore_ascii_case(&other.0)
96 }
97}
98
99impl Eq for CaseInsensitiveStr {}
100
101impl PartialOrd for CaseInsensitiveStr {
102 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103 Some(self.cmp(other))
104 }
105}
106
107impl Ord for CaseInsensitiveStr {
108 fn cmp(&self, other: &Self) -> Ordering {
109 self.0
110 .to_ascii_lowercase()
111 .cmp(&other.0.to_ascii_lowercase())
112 }
113}
114
115impl Deref for CaseInsensitiveStr {
116 type Target = str;
117 fn deref(&self) -> &Self::Target {
118 &self.0
119 }
120}
121
122impl std::fmt::Display for CaseInsensitiveStr {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 self.0.fmt(f)
125 }
126}
127
128impl Hash for CaseInsensitiveStr {
129 fn hash<H: Hasher>(&self, state: &mut H) {
130 self.0.to_ascii_lowercase().hash(state);
131 }
132}
133
134#[test]
135fn test_btree_map() {
136 let mut map = std::collections::BTreeMap::new();
137 map.insert(CaseInsensitiveString("hella".to_string()), 0);
138 map.insert(CaseInsensitiveString("Hello".to_string()), 1);
139 map.insert(CaseInsensitiveString("world".to_string()), 2);
140 assert_eq!(map.get(CaseInsensitiveStr::from_str("hello")), Some(&1));
141 assert_eq!(map.get(CaseInsensitiveStr::from_str("WORLD")), Some(&2));
142 assert_eq!(map.get(CaseInsensitiveStr::from_str("hella")), Some(&0));
143}
144
145#[test]
146fn test_hash_map() {
147 let mut map = std::collections::HashMap::new();
148 map.insert(CaseInsensitiveString("hells".to_string()), 0);
149 map.insert(CaseInsensitiveString("Hello".to_string()), 1);
150 map.insert(CaseInsensitiveString("world".to_string()), 2);
151 assert_eq!(map.get(CaseInsensitiveStr::from_str("hello")), Some(&1));
152 assert_eq!(map.get(CaseInsensitiveStr::from_str("WORLD")), Some(&2));
153 assert_eq!(map.get(CaseInsensitiveStr::from_str("hells")), Some(&0));
154}