aws_smithy_types/
str_bytes.rs1use bytes::Bytes;
9use std::str::Utf8Error;
10
11#[non_exhaustive]
36#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct StrBytes {
38    bytes: Bytes,
39}
40
41impl StrBytes {
42    fn new(bytes: Bytes) -> Self {
43        StrBytes { bytes }
44    }
45
46    pub fn as_bytes(&self) -> &Bytes {
48        &self.bytes
49    }
50
51    pub fn as_str(&self) -> &str {
53        unsafe { std::str::from_utf8_unchecked(&self.bytes[..]) }
55    }
56
57    pub fn try_copy_from_slice(slice: &[u8]) -> Result<Self, Utf8Error> {
60        match std::str::from_utf8(slice) {
61            Ok(_) => Ok(StrBytes::new(Bytes::copy_from_slice(slice))),
62            Err(err) => Err(err),
63        }
64    }
65
66    pub fn copy_from_str(string: &str) -> Self {
68        StrBytes::new(Bytes::copy_from_slice(string.as_bytes()))
69    }
70}
71
72impl From<String> for StrBytes {
73    fn from(value: String) -> Self {
74        StrBytes::new(Bytes::from(value))
75    }
76}
77
78impl From<&'static str> for StrBytes {
79    fn from(value: &'static str) -> Self {
80        StrBytes::new(Bytes::from(value))
81    }
82}
83
84impl TryFrom<&'static [u8]> for StrBytes {
85    type Error = Utf8Error;
86
87    fn try_from(value: &'static [u8]) -> Result<Self, Self::Error> {
88        match std::str::from_utf8(value) {
89            Ok(_) => Ok(StrBytes::new(Bytes::from(value))),
90            Err(err) => Err(err),
91        }
92    }
93}
94
95impl TryFrom<Vec<u8>> for StrBytes {
96    type Error = Utf8Error;
97
98    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
99        match std::str::from_utf8(&value[..]) {
100            Ok(_) => Ok(StrBytes::new(Bytes::from(value))),
101            Err(err) => Err(err),
102        }
103    }
104}
105
106impl TryFrom<Bytes> for StrBytes {
107    type Error = Utf8Error;
108
109    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
110        match std::str::from_utf8(&bytes[..]) {
111            Ok(_) => Ok(StrBytes::new(bytes)),
112            Err(err) => Err(err),
113        }
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use crate::str_bytes::StrBytes;
120    use bytes::Bytes;
121    use std::str::Utf8Error;
122
123    #[test]
124    fn invalid_utf8_correctly_errors() {
125        let invalid_utf8 = &[0xC3, 0x28][..];
126        assert!(std::str::from_utf8(invalid_utf8).is_err());
127
128        let result: Result<StrBytes, Utf8Error> = invalid_utf8.try_into();
129        assert!(result.is_err());
130
131        let result: Result<StrBytes, Utf8Error> = invalid_utf8.to_vec().try_into();
132        assert!(result.is_err());
133
134        let result: Result<StrBytes, Utf8Error> = Bytes::from_static(invalid_utf8).try_into();
135        assert!(result.is_err());
136    }
137
138    #[test]
139    fn valid_utf8() {
140        let valid_utf8 = "hello";
141        let str_bytes: StrBytes = valid_utf8.into();
142        assert_eq!(valid_utf8.as_bytes(), str_bytes.as_bytes());
143        assert_eq!(valid_utf8, str_bytes.as_str());
144        assert_eq!(valid_utf8, str_bytes.as_str());
145    }
146
147    #[test]
148    fn equals() {
149        let str_bytes: StrBytes = "test".into();
150        assert_eq!(str_bytes, str_bytes);
151        let other_bytes: StrBytes = "foo".into();
152        assert_ne!(str_bytes, other_bytes);
153    }
154}