static_or_heap_string/
lib.rs1#![no_std]
2
3extern crate alloc;
4
5use alloc::string::{String,ToString};
6use serde::*;
7use core::fmt;
8use core::cmp::Ordering;
9use core::hash::{Hash, Hasher};
10
11#[derive(Clone, Eq)]
13pub enum StaticOrHeapString {
14 Static(&'static str),
15 Heap(String),
16}
17
18impl PartialEq for StaticOrHeapString {
19 fn eq(&self, other: &Self) -> bool {
20 self.as_str() == other.as_str()
21 }
22}
23
24impl PartialOrd for StaticOrHeapString {
25 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
26 Some(self.as_str().cmp(other.as_str()))
27 }
28}
29
30impl Ord for StaticOrHeapString {
31 fn cmp(&self, other: &Self) -> Ordering {
32 self.as_str().cmp(other.as_str())
33 }
34}
35
36impl fmt::Debug for StaticOrHeapString {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(f, "{}", self.as_str())
39 }
40}
41
42impl<'de> Deserialize<'de> for StaticOrHeapString {
43 fn deserialize<D>(deserializer: D) -> Result<StaticOrHeapString, D::Error>
44 where
45 D: Deserializer<'de>,
46 {
47 let heap_key: String = Deserialize::deserialize(deserializer)?;
48 Ok(StaticOrHeapString::Heap(heap_key))
49 }
50}
51
52impl Serialize for StaticOrHeapString {
53 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
55 where
56 S: serde::ser::Serializer,
57 {
58 serializer.serialize_str(self.as_str())
59 }
60}
61
62impl StaticOrHeapString {
63 pub fn as_str(&self) -> &str {
65 match self {
66 StaticOrHeapString::Static(s) => s,
67 StaticOrHeapString::Heap(s) => s.as_str(),
68 }
69 }
70
71 pub fn as_mut_str(&mut self) -> &mut str {
73 match self {
74 StaticOrHeapString::Static(s) => {
75 let heap_string = s.to_string();
77 *self = StaticOrHeapString::Heap(heap_string);
78 match self {
79 StaticOrHeapString::Heap(s) => s.as_mut_str(),
80 _ => unreachable!(),
81 }
82 }
83 StaticOrHeapString::Heap(s) => s.as_mut_str(),
84 }
85 }
86
87 pub fn is_empty(&self) -> bool {
89 self.as_str().is_empty()
90 }
91
92 pub fn len(&self) -> usize {
94 self.as_str().len()
95 }
96}
97
98impl Hash for StaticOrHeapString {
99 fn hash<H: Hasher>(&self, state: &mut H) {
100 self.as_str().hash(state);
101 }
102}
103
104impl From<&'static str> for StaticOrHeapString {
105 fn from(s: &'static str) -> Self {
106 StaticOrHeapString::Static(s)
107 }
108}
109
110impl From<String> for StaticOrHeapString {
111 fn from(s: String) -> Self {
112 StaticOrHeapString::Heap(s)
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use serde_json;
120 use core::hash::Hash;
121 use core::hash::{BuildHasherDefault,BuildHasher};
122 use twox_hash::XxHash64;
123 use alloc::format;
124
125 #[test]
126 fn test_static_or_heap_string_can_serde_roundtrip() {
127 let static_str = StaticOrHeapString::Static("hello");
129 let serialized = serde_json::to_string(&static_str).unwrap();
130 let deserialized: StaticOrHeapString = serde_json::from_str(&serialized).unwrap();
131 assert_eq!(static_str, deserialized);
132
133 let heap_str = StaticOrHeapString::Heap(String::from("world"));
135 let serialized = serde_json::to_string(&heap_str).unwrap();
136 let deserialized: StaticOrHeapString = serde_json::from_str(&serialized).unwrap();
137 assert_eq!(heap_str, deserialized);
138 }
139
140 #[test]
141 fn test_static_or_heap_string_partial_eq() {
142 let static_str1 = StaticOrHeapString::Static("hello");
143 let static_str2 = StaticOrHeapString::Static("hello");
144 let heap_str1 = StaticOrHeapString::Heap(String::from("hello"));
145 let heap_str2 = StaticOrHeapString::Heap(String::from("world"));
146
147 assert_eq!(static_str1, static_str2);
148 assert_eq!(static_str1, heap_str1);
149 assert_ne!(static_str1, heap_str2);
150 }
151
152 #[test]
153 fn test_static_or_heap_string_partial_ord() {
154 let static_str1 = StaticOrHeapString::Static("apple");
155 let static_str2 = StaticOrHeapString::Static("banana");
156 let heap_str1 = StaticOrHeapString::Heap(String::from("apple"));
157 let heap_str2 = StaticOrHeapString::Heap(String::from("banana"));
158
159 assert!(static_str1 < static_str2);
160 assert!(heap_str1 < heap_str2);
161 assert!(static_str1 <= heap_str1);
162 assert!(static_str2 > heap_str1);
163 }
164
165 #[test]
166 fn test_static_or_heap_string_ord() {
167 let static_str1 = StaticOrHeapString::Static("apple");
168 let heap_str1 = StaticOrHeapString::Heap(String::from("apple"));
169 let static_str2 = StaticOrHeapString::Static("banana");
170 let heap_str2 = StaticOrHeapString::Heap(String::from("banana"));
171
172 assert_eq!(static_str1.cmp(&heap_str1), Ordering::Equal);
173 assert_eq!(static_str1.cmp(&static_str2), Ordering::Less);
174 assert_eq!(heap_str2.cmp(&static_str1), Ordering::Greater);
175 }
176
177 #[test]
178 fn test_static_or_heap_string_debug() {
179 let static_str = StaticOrHeapString::Static("hello");
180 let heap_str = StaticOrHeapString::Heap(String::from("world"));
181
182 assert_eq!(format!("{:?}", static_str), "hello");
183 assert_eq!(format!("{:?}", heap_str), "world");
184 }
185
186 #[test]
187 fn test_static_or_heap_string_as_str() {
188 let static_str = StaticOrHeapString::Static("hello");
189 let heap_str = StaticOrHeapString::Heap(String::from("world"));
190
191 assert_eq!(static_str.as_str(), "hello");
192 assert_eq!(heap_str.as_str(), "world");
193 }
194
195 #[test]
196 fn test_static_or_heap_string_clone() {
197 let static_str = StaticOrHeapString::Static("hello");
198 let heap_str = StaticOrHeapString::Heap(String::from("world"));
199
200 let cloned_static = static_str.clone();
201 let cloned_heap = heap_str.clone();
202
203 assert_eq!(static_str, cloned_static);
204 assert_eq!(heap_str, cloned_heap);
205 }
206
207 #[test]
208 fn test_static_or_heap_string_hash() {
209 type MyHasher = BuildHasherDefault<XxHash64>;
210
211 let static_str = StaticOrHeapString::Static("hello");
212 let heap_str = StaticOrHeapString::Heap(String::from("hello"));
213
214 let mut hasher1 = MyHasher::default().build_hasher();
215 static_str.hash(&mut hasher1);
216 let hash1 = hasher1.finish();
217
218 let mut hasher2 = MyHasher::default().build_hasher();
219 heap_str.hash(&mut hasher2);
220 let hash2 = hasher2.finish();
221
222 assert_eq!(hash1, hash2);
223 }
224}