protobuf/
chars.rs

1#![cfg(feature = "bytes")]
2
3use std::borrow::Borrow;
4use std::fmt;
5use std::ops::Deref;
6use std::str;
7
8use 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)]
13pub struct Chars(Bytes);
14
15impl Chars {
16    /// New empty object.
17    pub const fn new() -> Chars {
18        Chars(Bytes::new())
19    }
20
21    /// Clear the buffer.
22    pub fn clear(&mut self) {
23        self.0.clear();
24    }
25
26    /// Try convert from `Bytes`
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.
34    pub fn len(&self) -> usize {
35        self.0.len()
36    }
37
38    /// Self-explanatory
39    pub fn is_empty(&self) -> bool {
40        self.0.is_empty()
41    }
42}
43
44impl<'a> From<&'a str> for Chars {
45    fn from(src: &'a str) -> Chars {
46        Chars(Bytes::copy_from_slice(src.as_bytes()))
47    }
48}
49
50impl From<String> for Chars {
51    fn from(src: String) -> Chars {
52        Chars(Bytes::from(src))
53    }
54}
55
56impl Into<String> for Chars {
57    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
63impl Default for Chars {
64    fn default() -> Self {
65        Chars::new()
66    }
67}
68
69impl Deref for Chars {
70    type Target = str;
71
72    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
78impl Borrow<str> for Chars {
79    fn borrow(&self) -> &str {
80        &*self
81    }
82}
83
84impl fmt::Display for Chars {
85    #[inline]
86    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        fmt::Display::fmt(&**self, f)
88    }
89}
90
91impl fmt::Debug for Chars {
92    #[inline]
93    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94        fmt::Debug::fmt(&**self, f)
95    }
96}
97
98#[cfg(test)]
99mod 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
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}