1use std::{borrow, fmt, hash, ops, slice, str};
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]
145 pub fn trimdown(&mut self) {
146 self.0.trimdown();
147 }
148
149 #[inline]
162 pub fn clear(&mut self) {
163 self.0.clear();
164 }
165
166 #[inline]
174 pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
175 Self(src)
176 }
177}
178
179impl PartialEq<str> for ByteString {
180 fn eq(&self, other: &str) -> bool {
181 &self[..] == other
182 }
183}
184
185impl<T: AsRef<str>> PartialEq<T> for ByteString {
186 fn eq(&self, other: &T) -> bool {
187 &self[..] == other.as_ref()
188 }
189}
190
191impl PartialEq<ByteString> for &ByteString {
192 fn eq(&self, other: &ByteString) -> bool {
193 self.as_str() == other.as_str()
194 }
195}
196
197impl PartialEq<ByteString> for str {
198 fn eq(&self, other: &ByteString) -> bool {
199 self == other.as_str()
200 }
201}
202
203impl PartialEq<ByteString> for &str {
204 fn eq(&self, other: &ByteString) -> bool {
205 *self == other.as_str()
206 }
207}
208
209impl AsRef<str> for ByteString {
210 #[inline]
211 fn as_ref(&self) -> &str {
212 self
213 }
214}
215
216impl hash::Hash for ByteString {
217 fn hash<H: hash::Hasher>(&self, state: &mut H) {
218 (**self).hash(state);
219 }
220}
221
222impl ops::Deref for ByteString {
223 type Target = str;
224
225 #[inline]
226 fn deref(&self) -> &str {
227 let bytes = self.0.as_ref();
228 unsafe { str::from_utf8_unchecked(bytes) }
231 }
232}
233
234impl borrow::Borrow<str> for ByteString {
235 #[inline]
236 fn borrow(&self) -> &str {
237 self
238 }
239}
240
241impl From<String> for ByteString {
242 #[inline]
243 fn from(value: String) -> Self {
244 Self(Bytes::from(value))
245 }
246}
247
248impl From<&str> for ByteString {
249 #[inline]
250 fn from(value: &str) -> Self {
251 Self(Bytes::copy_from_slice(value.as_ref()))
252 }
253}
254
255impl From<&ByteString> for ByteString {
256 #[inline]
257 fn from(value: &ByteString) -> Self {
258 value.clone()
259 }
260}
261
262impl<'a> From<borrow::Cow<'a, str>> for ByteString {
263 #[inline]
264 fn from(value: borrow::Cow<'a, str>) -> Self {
265 match value {
266 borrow::Cow::Owned(s) => Self::from(s),
267 borrow::Cow::Borrowed(s) => Self::from(s),
268 }
269 }
270}
271
272impl TryFrom<&[u8]> for ByteString {
273 type Error = ();
274
275 #[inline]
276 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
277 if utf8::is_valid(value) {
278 Ok(ByteString(Bytes::copy_from_slice(value)))
279 } else {
280 Err(())
281 }
282 }
283}
284
285impl TryFrom<Vec<u8>> for ByteString {
286 type Error = ();
287
288 #[inline]
289 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
290 if utf8::is_valid(&value) {
291 Ok(ByteString(Bytes::from(value)))
292 } else {
293 Err(())
294 }
295 }
296}
297
298impl TryFrom<Bytes> for ByteString {
299 type Error = ();
300
301 #[inline]
302 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
303 if utf8::is_valid(&value) {
304 Ok(ByteString(value))
305 } else {
306 Err(())
307 }
308 }
309}
310
311impl TryFrom<&Bytes> for ByteString {
312 type Error = ();
313
314 #[inline]
315 fn try_from(value: &Bytes) -> Result<Self, Self::Error> {
316 if utf8::is_valid(value) {
317 Ok(ByteString(value.clone()))
318 } else {
319 Err(())
320 }
321 }
322}
323
324impl TryFrom<BytesMut> for ByteString {
325 type Error = ();
326
327 #[inline]
328 fn try_from(value: BytesMut) -> Result<Self, Self::Error> {
329 if utf8::is_valid(&value) {
330 Ok(ByteString(value.freeze()))
331 } else {
332 Err(())
333 }
334 }
335}
336
337impl fmt::Debug for ByteString {
338 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
339 (**self).fmt(fmt)
340 }
341}
342
343impl fmt::Display for ByteString {
344 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
345 (**self).fmt(fmt)
346 }
347}
348
349mod serde {
350 use serde::de::{Deserialize, Deserializer};
351 use serde::ser::{Serialize, Serializer};
352
353 use super::ByteString;
354
355 impl Serialize for ByteString {
356 #[inline]
357 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
358 where
359 S: Serializer,
360 {
361 serializer.serialize_str(self.as_ref())
362 }
363 }
364
365 impl<'de> Deserialize<'de> for ByteString {
366 #[inline]
367 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
368 where
369 D: Deserializer<'de>,
370 {
371 String::deserialize(deserializer).map(ByteString::from)
372 }
373 }
374}
375
376#[cfg(feature = "simd")]
377mod utf8 {
378 pub(super) fn is_valid(input: &[u8]) -> bool {
379 simdutf8::basic::from_utf8(input).is_ok()
380 }
381}
382
383#[cfg(not(feature = "simd"))]
384mod utf8 {
385 pub(super) fn is_valid(input: &[u8]) -> bool {
386 std::str::from_utf8(input).is_ok()
387 }
388}
389
390#[cfg(test)]
391mod test {
392 use std::borrow::{Borrow, Cow};
393 use std::collections::hash_map::DefaultHasher;
394 use std::hash::{Hash, Hasher};
395
396 use super::*;
397
398 #[test]
399 fn test_basics() {
400 let mut s = ByteString::from_static("test");
401 s.trimdown();
402 assert_eq!(s, "test");
403 assert_eq!(s, *"test");
404 assert_eq!(s, "test".to_owned());
405 assert_eq!(s.as_str(), "test");
406 assert_eq!(s.as_slice(), b"test");
407 assert_eq!(s.as_bytes(), &Bytes::copy_from_slice(b"test"));
408 assert_eq!(Borrow::<str>::borrow(&s), "test");
409 assert_eq!("test", s);
410 assert_eq!("test", &s);
411
412 assert_eq!(format!("{s}"), "test");
413 assert_eq!(format!("{s:?}"), "\"test\"");
414
415 let b = s.into_bytes();
416 assert_eq!(b, Bytes::copy_from_slice(b"test"));
417
418 let s = unsafe { ByteString::from_bytes_unchecked(b) };
419 assert_eq!(s, "test");
420 assert_eq!(s.slice(0..2), "te");
421
422 let s = ByteString::from(Cow::Borrowed("test"));
423 assert_eq!(s, "test");
424 let mut s = ByteString::from(Cow::Owned("test".to_string()));
425 assert_eq!(s, "test");
426
427 s.clear();
428 assert_eq!(s, "");
429 }
430
431 #[test]
432 fn test_split() {
433 let mut s = ByteString::from_static("helloworld");
434 let s1 = s.split_off(5);
435 assert_eq!(s, "hello");
436 assert_eq!(s1, "world");
437
438 let mut s = ByteString::from_static("helloworld");
439 let s1 = s.split_to(5);
440 assert_eq!(s, "world");
441 assert_eq!(s1, "hello");
442 }
443
444 #[test]
445 fn test_new() {
446 let _: ByteString = ByteString::new();
447 }
448
449 #[test]
450 fn test_hash() {
451 let mut hasher1 = DefaultHasher::default();
452 "str".hash(&mut hasher1);
453
454 let mut hasher2 = DefaultHasher::default();
455 let s = ByteString::from_static("str");
456 s.hash(&mut hasher2);
457 assert_eq!(hasher1.finish(), hasher2.finish());
458 }
459
460 #[test]
461 #[allow(clippy::items_after_statements)]
462 fn test_from() {
463 let s: ByteString = "hello".to_owned().into();
465 assert_eq!(&s, "hello");
466 let t: &str = s.as_ref();
467 assert_eq!(t, "hello");
468
469 let _: ByteString = "str".into();
471
472 static _S: ByteString = ByteString::from_static("hello");
474 let _ = ByteString::from_static("str");
475
476 let s = ByteString::from_static("hello");
477 let s1 = ByteString::from(&s);
478 assert_eq!(s1, "hello");
479 }
480
481 #[test]
482 fn test_try_from() {
483 let _ = ByteString::try_from(&b"nice bytes"[..]).unwrap();
484 assert!(ByteString::try_from(b"\xc3\x28".as_ref()).is_err());
485
486 let _ = ByteString::try_from(b"nice bytes".to_vec()).unwrap();
487 assert!(ByteString::try_from(vec![b'\xc3']).is_err());
488
489 let _ = ByteString::try_from(Bytes::from_static(b"nice bytes")).unwrap();
490 assert!(ByteString::try_from(Bytes::from_static(b"\xc3\x28")).is_err());
491
492 let _ = ByteString::try_from(&Bytes::from_static(b"nice bytes")).unwrap();
493 assert!(ByteString::try_from(&Bytes::from_static(b"\xc3\x28")).is_err());
494
495 let _ =
496 ByteString::try_from(BytesMut::copy_from_slice(&b"nice bytes"[..])).unwrap();
497 assert!(ByteString::try_from(BytesMut::copy_from_slice(b"\xc3\x28")).is_err());
498 }
499
500 #[test]
501 fn test_serialize() {
502 let s: ByteString = serde_json::from_str(r#""nice bytes""#).unwrap();
503 assert_eq!(s, "nice bytes");
504 }
505
506 #[test]
507 fn test_deserialize() {
508 let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap();
509 assert_eq!(s, r#""nice bytes""#);
510 }
511}