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