terrazzo_client/
string.rs1use std::borrow::Borrow;
4use std::hash::Hash;
5use std::ops::Deref;
6use std::sync::Arc;
7
8#[derive(Debug, Clone)]
10pub enum XString {
11 Str(&'static str),
12 Ref(Arc<str>),
13}
14
15impl XString {
16 #[must_use]
17 pub fn as_str(&self) -> &str {
18 match self {
19 XString::Str(str) => str,
20 XString::Ref(arc) => arc.as_ref(),
21 }
22 }
23}
24
25impl AsRef<str> for XString {
26 fn as_ref(&self) -> &str {
27 self.as_str()
28 }
29}
30
31impl Deref for XString {
32 type Target = str;
33
34 fn deref(&self) -> &Self::Target {
35 self.as_ref()
36 }
37}
38
39impl Borrow<str> for XString {
40 fn borrow(&self) -> &str {
41 self.as_str()
42 }
43}
44
45impl std::fmt::Display for XString {
46 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
47 std::fmt::Display::fmt(self.as_str(), f)
48 }
49}
50
51impl Default for XString {
52 fn default() -> Self {
53 Self::Str("")
54 }
55}
56
57impl PartialEq for XString {
58 fn eq(&self, other: &Self) -> bool {
59 PartialEq::eq(self.as_str(), other.as_str())
60 }
61}
62
63impl Eq for XString {}
64
65impl PartialOrd for XString {
66 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
67 Some(Ord::cmp(&self, &other))
68 }
69}
70
71impl Ord for XString {
72 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
73 Ord::cmp(self.as_str(), other.as_str())
74 }
75}
76
77impl Hash for XString {
78 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
79 Hash::hash(self.as_str(), state);
80 }
81}
82
83impl From<String> for XString {
84 fn from(string: String) -> Self {
85 Self::Ref(string.into())
86 }
87}
88
89impl From<&'static str> for XString {
90 fn from(str: &'static str) -> Self {
91 Self::Str(str)
92 }
93}
94
95impl From<Arc<str>> for XString {
96 fn from(arc: Arc<str>) -> Self {
97 Self::Ref(arc)
98 }
99}
100
101impl From<bool> for XString {
102 fn from(t: bool) -> Self {
103 Self::Str(if t { "true" } else { "false" })
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use std::collections::HashSet;
110 use std::sync::Arc;
111
112 use super::XString;
113
114 #[test]
115 fn from_str() {
116 let xs: XString = "value".into();
117 assert_eq!(format!(" {xs:?} "), r#" Str("value") "#);
118 }
119
120 #[test]
121 fn from_arc() {
122 let s: Arc<str> = "value".into();
123 let xs: XString = s.into();
124 assert_eq!(format!(" {xs:?} "), r#" Ref("value") "#);
125 }
126
127 #[test]
128 fn eq() {
129 assert_eq!(XString::Str("A"), XString::Str("A"));
130 assert_eq!(XString::Str("A"), XString::Ref("A".into()));
131 assert_eq!(XString::Ref("A".into()), XString::Ref("A".into()));
132 }
133
134 #[test]
135 fn ne() {
136 assert_ne!(XString::Str("A"), XString::Str("B"));
137 assert_ne!(XString::Str("A"), XString::Ref("B".into()));
138 }
139
140 #[test]
141 fn ord() {
142 let mut strings = vec![
143 XString::Ref("b-arc".into()),
144 XString::Str("a-str"),
145 XString::Str("d-str"),
146 XString::Ref("c-arc".into()),
147 ];
148
149 strings.sort();
150 assert_eq!(
151 vec![
152 XString::Str("a-str"),
153 XString::Ref("b-arc".into()),
154 XString::Ref("c-arc".into()),
155 XString::Str("d-str"),
156 ],
157 strings
158 );
159 }
160
161 #[test]
162 fn hash() {
163 let strings = [
164 XString::Str("a-str"),
165 XString::Ref("b-arc".into()),
166 XString::Ref("c-arc".into()),
167 XString::Str("d-str"),
168 ]
169 .into_iter()
170 .collect::<HashSet<_>>();
171
172 assert!(strings.contains("a-str"));
173 assert!(strings.contains("b-arc"));
174 assert!(strings.contains("c-arc"));
175 assert!(strings.contains("d-str"));
176
177 assert!(strings.contains(&XString::from("a-str")));
178 assert!(strings.contains(&XString::from("a-str".to_string())));
179
180 assert!(!strings.contains("x"));
181 assert!(!strings.contains(&XString::from("y")));
182 }
183}