1 #![cfg(feature = "bytes")] 2 3 use std::borrow::Borrow; 4 use std::fmt; 5 use std::ops::Deref; 6 use std::str; 7 8 use bytes::Bytes; 9 10 /// Thin wrapper around `Bytes` which guarantees that bytes are valid UTF-8 string. 11 /// Should be API-compatible to `String`. 12 #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] 13 pub struct Chars(Bytes); 14 15 impl Chars { 16 /// New empty object. new() -> Chars17 pub const fn new() -> Chars { 18 Chars(Bytes::new()) 19 } 20 21 /// Clear the buffer. clear(&mut self)22 pub fn clear(&mut self) { 23 self.0.clear(); 24 } 25 26 /// Try convert from `Bytes` from_bytes(bytes: Bytes) -> Result<Chars, str::Utf8Error>27 pub fn from_bytes(bytes: Bytes) -> Result<Chars, str::Utf8Error> { 28 str::from_utf8(&bytes)?; 29 30 Ok(Chars(bytes)) 31 } 32 33 /// Len in bytes. len(&self) -> usize34 pub fn len(&self) -> usize { 35 self.0.len() 36 } 37 38 /// Self-explanatory is_empty(&self) -> bool39 pub fn is_empty(&self) -> bool { 40 self.0.is_empty() 41 } 42 } 43 44 impl<'a> From<&'a str> for Chars { from(src: &'a str) -> Chars45 fn from(src: &'a str) -> Chars { 46 Chars(Bytes::copy_from_slice(src.as_bytes())) 47 } 48 } 49 50 impl From<String> for Chars { from(src: String) -> Chars51 fn from(src: String) -> Chars { 52 Chars(Bytes::from(src)) 53 } 54 } 55 56 impl Into<String> for Chars { into(self) -> String57 fn into(self) -> String { 58 // This is safe because `Chars` is guaranteed to store a valid UTF-8 string 59 unsafe { String::from_utf8_unchecked(self.0.as_ref().to_owned()) } 60 } 61 } 62 63 impl Default for Chars { default() -> Self64 fn default() -> Self { 65 Chars::new() 66 } 67 } 68 69 impl Deref for Chars { 70 type Target = str; 71 deref(&self) -> &str72 fn deref(&self) -> &str { 73 // This is safe because `Chars` is guaranteed to store a valid UTF-8 string 74 unsafe { str::from_utf8_unchecked(&self.0) } 75 } 76 } 77 78 impl Borrow<str> for Chars { borrow(&self) -> &str79 fn borrow(&self) -> &str { 80 &*self 81 } 82 } 83 84 impl fmt::Display for Chars { 85 #[inline] fmt(&self, f: &mut fmt::Formatter) -> fmt::Result86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 87 fmt::Display::fmt(&**self, f) 88 } 89 } 90 91 impl fmt::Debug for Chars { 92 #[inline] fmt(&self, f: &mut fmt::Formatter) -> fmt::Result93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 94 fmt::Debug::fmt(&**self, f) 95 } 96 } 97 98 #[cfg(test)] 99 mod test { 100 use super::Chars; 101 102 #[test] 103 #[cfg_attr(miri, ignore)] // bytes violates SB, see https://github.com/tokio-rs/bytes/issues/522 test_display_and_debug()104 fn test_display_and_debug() { 105 let s = "test"; 106 let string: String = s.into(); 107 let chars: Chars = s.into(); 108 109 assert_eq!(format!("{}", string), format!("{}", chars)); 110 assert_eq!(format!("{:?}", string), format!("{:?}", chars)); 111 } 112 } 113