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