terrazzo_client/
string.rs

1//! Copy-friendly strings or static &str.
2
3use std::borrow::Borrow;
4use std::hash::Hash;
5use std::ops::Deref;
6use std::sync::Arc;
7
8/// Represents a string that is cheap to copy.
9#[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}