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