1use std::{borrow, fmt, hash, ops, slice, str, sync::Arc};
3
4use crate::{Bytes, BytesMut};
5
6#[derive(Clone, Default, Eq, PartialOrd, Ord)]
8pub struct ByteString(Bytes);
9
10impl ByteString {
11 #[inline]
13 #[must_use]
14 pub const fn new() -> Self {
15 ByteString(Bytes::new())
16 }
17
18 #[inline]
20 pub fn as_str(&self) -> &str {
21 self
22 }
23
24 #[inline]
26 pub fn as_slice(&self) -> &[u8] {
27 self.0.as_ref()
28 }
29
30 #[inline]
32 pub fn as_bytes(&self) -> &Bytes {
33 &self.0
34 }
35
36 #[inline]
38 #[must_use]
39 pub fn into_bytes(self) -> Bytes {
40 self.0
41 }
42
43 #[inline]
45 #[must_use]
46 pub const fn from_static(src: &'static str) -> ByteString {
47 Self(Bytes::from_static(src.as_bytes()))
48 }
49
50 #[must_use]
73 pub fn slice(
74 &self,
75 range: impl ops::RangeBounds<usize> + slice::SliceIndex<str> + Clone,
76 ) -> ByteString {
77 ops::Index::index(self.as_ref(), range.clone());
78 ByteString(self.0.slice(range))
79 }
80
81 #[must_use]
105 pub fn split_off(&mut self, at: usize) -> ByteString {
106 let _ = self.split_at(at);
108
109 ByteString(self.0.split_off(at))
110 }
111
112 #[must_use]
136 pub fn split_to(&mut self, at: usize) -> ByteString {
137 let _ = self.split_at(at);
139
140 ByteString(self.0.split_to(at))
141 }
142
143 #[inline]
147 pub fn trimdown(&mut self) {
148 self.0.trimdown();
149 }
150
151 #[inline]
164 pub fn clear(&mut self) {
165 self.0.clear();
166 }
167
168 #[inline]
176 pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
177 Self(src)
178 }
179}
180
181impl PartialEq<str> for ByteString {
182 fn eq(&self, other: &str) -> bool {
183 &self[..] == other
184 }
185}
186
187impl<T: AsRef<str>> PartialEq<T> for ByteString {
188 fn eq(&self, other: &T) -> bool {
189 &self[..] == other.as_ref()
190 }
191}
192
193impl PartialEq<ByteString> for &ByteString {
194 fn eq(&self, other: &ByteString) -> bool {
195 self.as_str() == other.as_str()
196 }
197}
198
199impl PartialEq<ByteString> for str {
200 fn eq(&self, other: &ByteString) -> bool {
201 self == other.as_str()
202 }
203}
204
205impl PartialEq<ByteString> for &str {
206 fn eq(&self, other: &ByteString) -> bool {
207 *self == other.as_str()
208 }
209}
210
211impl AsRef<str> for ByteString {
212 #[inline]
213 fn as_ref(&self) -> &str {
214 self
215 }
216}
217
218impl hash::Hash for ByteString {
219 fn hash<H: hash::Hasher>(&self, state: &mut H) {
220 (**self).hash(state);
221 }
222}
223
224impl ops::Deref for ByteString {
225 type Target = str;
226
227 #[inline]
228 fn deref(&self) -> &str {
229 let bytes = self.0.as_ref();
230 unsafe { str::from_utf8_unchecked(bytes) }
233 }
234}
235
236impl borrow::Borrow<str> for ByteString {
237 #[inline]
238 fn borrow(&self) -> &str {
239 self
240 }
241}
242
243impl From<String> for ByteString {
244 #[inline]
245 fn from(value: String) -> Self {
246 Self(Bytes::from(value))
247 }
248}
249
250impl From<&str> for ByteString {
251 #[inline]
252 fn from(value: &str) -> Self {
253 Self(Bytes::copy_from_slice(value.as_ref()))
254 }
255}
256
257impl From<&ByteString> for ByteString {
258 #[inline]
259 fn from(value: &ByteString) -> Self {
260 value.clone()
261 }
262}
263
264impl<'a> From<borrow::Cow<'a, str>> for ByteString {
265 #[inline]
266 fn from(value: borrow::Cow<'a, str>) -> Self {
267 match value {
268 borrow::Cow::Owned(s) => Self::from(s),
269 borrow::Cow::Borrowed(s) => Self::from(s),
270 }
271 }
272}
273
274impl From<Arc<str>> for ByteString {
275 #[inline]
276 fn from(value: Arc<str>) -> Self {
277 ByteString::from_ext(value)
278 }
279}
280
281impl TryFrom<&[u8]> for ByteString {
282 type Error = ();
283
284 #[inline]
285 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
286 if utf8::is_valid(value) {
287 Ok(ByteString(Bytes::copy_from_slice(value)))
288 } else {
289 Err(())
290 }
291 }
292}
293
294impl TryFrom<Vec<u8>> for ByteString {
295 type Error = ();
296
297 #[inline]
298 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
299 if utf8::is_valid(&value) {
300 Ok(ByteString(Bytes::from(value)))
301 } else {
302 Err(())
303 }
304 }
305}
306
307impl TryFrom<Bytes> for ByteString {
308 type Error = ();
309
310 #[inline]
311 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
312 if utf8::is_valid(&value) {
313 Ok(ByteString(value))
314 } else {
315 Err(())
316 }
317 }
318}
319
320impl TryFrom<&Bytes> for ByteString {
321 type Error = ();
322
323 #[inline]
324 fn try_from(value: &Bytes) -> Result<Self, Self::Error> {
325 if utf8::is_valid(value) {
326 Ok(ByteString(value.clone()))
327 } else {
328 Err(())
329 }
330 }
331}
332
333impl TryFrom<BytesMut> for ByteString {
334 type Error = ();
335
336 #[inline]
337 fn try_from(value: BytesMut) -> Result<Self, Self::Error> {
338 if utf8::is_valid(&value) {
339 Ok(ByteString(value.freeze()))
340 } else {
341 Err(())
342 }
343 }
344}
345
346impl fmt::Debug for ByteString {
347 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
348 (**self).fmt(fmt)
349 }
350}
351
352impl fmt::Display for ByteString {
353 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
354 (**self).fmt(fmt)
355 }
356}
357
358mod serde {
359 use serde::de::{Deserialize, Deserializer};
360 use serde::ser::{Serialize, Serializer};
361
362 use super::ByteString;
363
364 impl Serialize for ByteString {
365 #[inline]
366 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
367 where
368 S: Serializer,
369 {
370 serializer.serialize_str(self.as_ref())
371 }
372 }
373
374 impl<'de> Deserialize<'de> for ByteString {
375 #[inline]
376 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
377 where
378 D: Deserializer<'de>,
379 {
380 String::deserialize(deserializer).map(ByteString::from)
381 }
382 }
383}
384
385#[cfg(feature = "simd")]
386mod utf8 {
387 pub(super) fn is_valid(input: &[u8]) -> bool {
388 simdutf8::basic::from_utf8(input).is_ok()
389 }
390}
391
392#[cfg(not(feature = "simd"))]
393mod utf8 {
394 pub(super) fn is_valid(input: &[u8]) -> bool {
395 std::str::from_utf8(input).is_ok()
396 }
397}
398
399#[cfg(test)]
400mod test {
401 use std::borrow::{Borrow, Cow};
402 use std::collections::hash_map::DefaultHasher;
403 use std::hash::{Hash, Hasher};
404
405 use super::*;
406
407 #[test]
408 fn test_basics() {
409 let mut s = ByteString::from_static("test");
410 s.trimdown();
411 assert_eq!(s, "test");
412 assert_eq!(s, *"test");
413 assert_eq!(s, "test".to_owned());
414 assert_eq!(s.as_str(), "test");
415 assert_eq!(s.as_slice(), b"test");
416 assert_eq!(s.as_bytes(), &Bytes::copy_from_slice(b"test"));
417 assert_eq!(Borrow::<str>::borrow(&s), "test");
418 assert_eq!("test", s);
419 assert_eq!("test", &s);
420
421 assert_eq!(format!("{s}"), "test");
422 assert_eq!(format!("{s:?}"), "\"test\"");
423
424 let b = s.into_bytes();
425 assert_eq!(b, Bytes::copy_from_slice(b"test"));
426
427 let s = unsafe { ByteString::from_bytes_unchecked(b) };
428 assert_eq!(s, "test");
429 assert_eq!(s.slice(0..2), "te");
430
431 let s = ByteString::from(Cow::Borrowed("test"));
432 assert_eq!(s, "test");
433 let mut s = ByteString::from(Cow::Owned("test".to_string()));
434 assert_eq!(s, "test");
435
436 s.clear();
437 assert_eq!(s, "");
438 }
439
440 #[test]
441 fn test_split() {
442 let mut s = ByteString::from_static("helloworld");
443 let s1 = s.split_off(5);
444 assert_eq!(s, "hello");
445 assert_eq!(s1, "world");
446
447 let mut s = ByteString::from_static("helloworld");
448 let s1 = s.split_to(5);
449 assert_eq!(s, "world");
450 assert_eq!(s1, "hello");
451 }
452
453 #[test]
454 fn test_new() {
455 let _: ByteString = ByteString::new();
456 }
457
458 #[test]
459 fn test_hash() {
460 let mut hasher1 = DefaultHasher::default();
461 "str".hash(&mut hasher1);
462
463 let mut hasher2 = DefaultHasher::default();
464 let s = ByteString::from_static("str");
465 s.hash(&mut hasher2);
466 assert_eq!(hasher1.finish(), hasher2.finish());
467 }
468
469 #[test]
470 #[allow(clippy::items_after_statements)]
471 fn test_from() {
472 let s: ByteString = "hello".to_owned().into();
474 assert_eq!(&s, "hello");
475 let t: &str = s.as_ref();
476 assert_eq!(t, "hello");
477
478 let _: ByteString = "str".into();
480
481 static _S: ByteString = ByteString::from_static("hello");
483 let _ = ByteString::from_static("str");
484
485 let s = ByteString::from_static("hello");
486 let s1 = ByteString::from(&s);
487 assert_eq!(s1, "hello");
488 }
489
490 #[test]
491 fn test_try_from() {
492 let _ = ByteString::try_from(&b"nice bytes"[..]).unwrap();
493 assert!(ByteString::try_from(b"\xc3\x28".as_ref()).is_err());
494
495 let _ = ByteString::try_from(b"nice bytes".to_vec()).unwrap();
496 assert!(ByteString::try_from(vec![b'\xc3']).is_err());
497
498 let _ = ByteString::try_from(Bytes::from_static(b"nice bytes")).unwrap();
499 assert!(ByteString::try_from(Bytes::from_static(b"\xc3\x28")).is_err());
500
501 let _ = ByteString::try_from(&Bytes::from_static(b"nice bytes")).unwrap();
502 assert!(ByteString::try_from(&Bytes::from_static(b"\xc3\x28")).is_err());
503
504 let _ = ByteString::try_from(BytesMut::copy_from_slice(&b"nice bytes"[..])).unwrap();
505 assert!(ByteString::try_from(BytesMut::copy_from_slice(b"\xc3\x28")).is_err());
506 }
507
508 #[test]
509 fn test_serialize() {
510 let s: ByteString = serde_json::from_str(r#""nice bytes""#).unwrap();
511 assert_eq!(s, "nice bytes");
512 }
513
514 #[test]
515 fn test_deserialize() {
516 let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap();
517 assert_eq!(s, r#""nice bytes""#);
518 }
519
520 #[test]
521 fn test_ref_eq_and_arc() {
522 let s = ByteString::from_static("hello");
523 assert_eq!(&s, ByteString::from_static("hello"));
524 assert_ne!(&s, ByteString::from_static("world"));
525
526 let arc: std::sync::Arc<str> = "a long string that is not stored inline".into();
527 let s = ByteString::from(arc.clone());
528 assert_eq!(s, &*arc);
529 assert_eq!(std::sync::Arc::strong_count(&arc), 2);
530 drop(s);
531 assert_eq!(std::sync::Arc::strong_count(&arc), 1);
532 }
533}