1use core::{
2 borrow::Borrow,
3 cmp::{Eq, Ord, PartialEq, PartialOrd},
4 convert::TryFrom,
5 fmt,
6 hash::{Hash, Hasher},
7 ops::{self, Deref, DerefMut, Index, IndexMut},
8 str,
9};
10
11use self::builder::StringBuilder;
12use crate::error::Error;
13
14pub mod builder;
15#[cfg(feature = "rkyv-derive")]
16pub mod rkyv;
17#[cfg(feature = "serde-derive")]
18pub mod serde;
19
20#[derive(Copy, Clone, Eq, PartialOrd, Ord)]
21pub struct String<const L: usize>(pub(crate) [u8; L]);
22
23impl<const L: usize> String<L> {
26 pub const fn empty() -> Self {
27 Self([b' '; L])
28 }
29
30 pub fn try_from_str_padded(s: impl AsRef<str>) -> Result<Self, Error> {
47 Self::try_from_bytes_padded(s.as_ref().as_bytes())
48 }
49
50 pub fn try_from_bytes_padded(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
63 let bytes = bytes.as_ref();
64
65 if bytes.len() > L {
66 return Err(Error::new(L, bytes.len()));
67 }
68
69 let mut builder = Self::builder();
70 unsafe {
71 builder.push_bytes_unchecked(bytes);
72 }
73
74 Ok(builder.build())
75 }
76
77 pub const fn builder() -> StringBuilder<L> {
78 StringBuilder::empty()
79 }
80
81 pub fn as_str(&self) -> &str {
82 &self
83 }
84
85 pub fn as_bytes(&self) -> &[u8; L] {
86 &self.0
87 }
88
89 pub fn as_slice(&self) -> &[u8] {
90 self.as_str().as_bytes()
91 }
92
93 pub fn into_bytes(self) -> [u8; L] {
95 self.0
96 }
97
98 pub fn is_empty(&self) -> bool {
100 self.0.iter().all(|&x| x == b' ')
101 }
102
103 pub fn starts_empty(&self) -> bool {
106 self.0[0] == b' '
107 }
108}
109
110impl<const L: usize> Default for String<L> {
111 fn default() -> Self {
112 Self::empty()
113 }
114}
115
116impl<const L: usize> fmt::Debug for String<L> {
117 #[inline]
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 fmt::Debug::fmt(&**self, f)
120 }
121}
122
123impl<const L: usize> fmt::Display for String<L> {
124 #[inline]
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 fmt::Display::fmt(&**self, f)
127 }
128}
129
130impl<const L: usize> Deref for String<L> {
131 type Target = str;
132
133 fn deref(&self) -> &str {
134 unsafe { core::str::from_utf8_unchecked(&self.0) }
135 }
136}
137
138impl<const L: usize> DerefMut for String<L> {
139 #[inline]
140 fn deref_mut(&mut self) -> &mut str {
141 unsafe { str::from_utf8_unchecked_mut(&mut self.0) }
142 }
143}
144
145impl<const L: usize> From<[u8; L]> for String<L> {
146 fn from(buf: [u8; L]) -> Self {
147 String(buf)
148 }
149}
150
151impl<const L: usize> Hash for String<L> {
152 #[inline]
153 fn hash<H: Hasher>(&self, hasher: &mut H) {
154 (**self).hash(hasher)
155 }
156}
157
158impl<const L: usize> TryFrom<&str> for String<L> {
159 type Error = crate::error::Error;
160
161 fn try_from(s: &str) -> Result<Self, Self::Error> {
162 if s.len() != L {
163 return Err(Error::new(L, s.len()));
164 }
165
166 let mut res = Self::empty();
167
168 res.0.copy_from_slice(s.as_bytes());
169
170 Ok(res)
171 }
172}
173
174impl<const L: usize> Borrow<str> for String<L> {
175 #[inline]
176 fn borrow(&self) -> &str {
177 &self
178 }
179}
180
181impl<const L: usize> PartialEq for String<L> {
182 #[inline]
183 fn eq(&self, other: &String<L>) -> bool {
184 PartialEq::eq(&self[..], &other[..])
185 }
186
187 #[inline]
188 fn ne(&self, other: &String<L>) -> bool {
189 PartialEq::ne(&self[..], &other[..])
190 }
191}
192
193impl<const L: usize> PartialEq<str> for String<L> {
195 #[inline]
196 fn eq(&self, other: &str) -> bool {
197 PartialEq::eq(&self[..], &other[..])
198 }
199
200 #[inline]
201 fn ne(&self, other: &str) -> bool {
202 PartialEq::ne(&self[..], &other[..])
203 }
204}
205
206impl<const L: usize> PartialEq<&str> for String<L> {
207 #[inline]
208 fn eq(&self, other: &&str) -> bool {
209 PartialEq::eq(&self[..], &other[..])
210 }
211
212 #[inline]
213 fn ne(&self, other: &&str) -> bool {
214 PartialEq::ne(&self[..], &other[..])
215 }
216}
217
218impl<const L: usize> PartialEq<String<L>> for &str {
219 #[inline]
220 fn eq(&self, other: &String<L>) -> bool {
221 PartialEq::eq(&self[..], &other[..])
222 }
223
224 #[inline]
225 fn ne(&self, other: &String<L>) -> bool {
226 PartialEq::ne(&self[..], &other[..])
227 }
228}
229
230impl<const L: usize> PartialEq<std::string::String> for String<L> {
232 #[inline]
233 fn eq(&self, other: &std::string::String) -> bool {
234 PartialEq::eq(&self[..], &other[..])
235 }
236
237 #[inline]
238 fn ne(&self, other: &std::string::String) -> bool {
239 PartialEq::ne(&self[..], &other[..])
240 }
241}
242
243impl<const L: usize> PartialEq<String<L>> for std::string::String {
244 #[inline]
245 fn eq(&self, other: &String<L>) -> bool {
246 PartialEq::eq(&self[..], &other[..])
247 }
248
249 #[inline]
250 fn ne(&self, other: &String<L>) -> bool {
251 PartialEq::ne(&self[..], &other[..])
252 }
253}
254
255impl<const L: usize> ops::Index<ops::Range<usize>> for String<L> {
256 type Output = str;
257
258 #[inline]
259 fn index(&self, index: ops::Range<usize>) -> &str {
260 &self[..][index]
261 }
262}
263
264impl<const L: usize> ops::Index<ops::RangeTo<usize>> for String<L> {
265 type Output = str;
266
267 #[inline]
268 fn index(&self, index: ops::RangeTo<usize>) -> &str {
269 &self[..][index]
270 }
271}
272
273impl<const L: usize> ops::Index<ops::RangeFrom<usize>> for String<L> {
274 type Output = str;
275
276 #[inline]
277 fn index(&self, index: ops::RangeFrom<usize>) -> &str {
278 &self[..][index]
279 }
280}
281
282impl<const L: usize> ops::Index<ops::RangeFull> for String<L> {
283 type Output = str;
284
285 #[inline]
286 fn index(&self, _index: ops::RangeFull) -> &str {
287 unsafe { str::from_utf8_unchecked(&self.0) }
288 }
289}
290
291impl<const L: usize> ops::Index<ops::RangeInclusive<usize>> for String<L> {
292 type Output = str;
293
294 #[inline]
295 fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
296 Index::index(&**self, index)
297 }
298}
299
300impl<const L: usize> ops::Index<ops::RangeToInclusive<usize>> for String<L> {
301 type Output = str;
302
303 #[inline]
304 fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
305 Index::index(&**self, index)
306 }
307}
308
309impl<const L: usize> ops::IndexMut<ops::Range<usize>> for String<L> {
310 #[inline]
311 fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
312 &mut self[..][index]
313 }
314}
315
316impl<const L: usize> ops::IndexMut<ops::RangeTo<usize>> for String<L> {
317 #[inline]
318 fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
319 &mut self[..][index]
320 }
321}
322
323impl<const L: usize> ops::IndexMut<ops::RangeFrom<usize>> for String<L> {
324 #[inline]
325 fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
326 &mut self[..][index]
327 }
328}
329
330impl<const L: usize> ops::IndexMut<ops::RangeFull> for String<L> {
331 #[inline]
332 fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
333 unsafe { str::from_utf8_unchecked_mut(&mut self.0) }
334 }
335}
336
337impl<const L: usize> ops::IndexMut<ops::RangeInclusive<usize>> for String<L> {
338 #[inline]
339 fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
340 IndexMut::index_mut(&mut **self, index)
341 }
342}
343
344impl<const L: usize> ops::IndexMut<ops::RangeToInclusive<usize>> for String<L> {
345 #[inline]
346 fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
347 IndexMut::index_mut(&mut **self, index)
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use super::*;
354 use std::collections::hash_map::DefaultHasher;
355 use std::collections::HashSet;
356 use std::hash::{Hash, Hasher};
357
358 #[test]
359 fn deref() {
360 let s_ = "abcde";
361 let s = String::<5>::try_from(s_).unwrap();
362
363 assert_eq!(s_, s);
364 }
365
366 #[test]
367 fn slice() {
368 let s = String::<3>::try_from("abc").unwrap();
369
370 assert_eq!(&s[..2], "ab");
371 }
372
373 #[test]
374 fn eq_impls() {
375 let s_ = "abcde";
376 let s = String::<5>::try_from(s_).unwrap();
377
378 assert_eq!(s_, s);
379
380 let s_ = s_.to_owned();
381 assert_eq!(s_, s);
382 }
383
384 #[test]
385 fn hash_set_contains() {
386 let s_ = "abcde";
387 let s = String::<5>::try_from(s_).unwrap();
388
389 assert_eq!(<String<5> as Borrow<str>>::borrow(&s), s_);
390
391 let mut hasher = DefaultHasher::new();
392 s_.hash(&mut hasher);
393 let s_hash = hasher.finish();
394 let mut hasher = DefaultHasher::new();
395 s.hash(&mut hasher);
396 let ss_hash = hasher.finish();
397
398 assert_eq!(s_hash, ss_hash);
399
400 let set = HashSet::from([s]);
401
402 assert!(set.contains(s_));
403
404 let s_ = s_.to_owned();
405 assert!(set.contains(s_.as_str()));
406 }
407}