http_wasm_guest/host/
bytes.rs1use std::{
2 borrow::Borrow,
3 fmt::Display,
4 ops::Deref,
5 str::{Utf8Error, from_utf8},
6};
7
8#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Hash, Default)]
16pub struct Bytes(Box<[u8]>);
17
18impl Bytes {
21 pub fn to_str(&self) -> Result<&str, Utf8Error> {
26 from_utf8(self.0.as_ref())
27 }
28}
29
30impl Deref for Bytes {
33 type Target = [u8];
34
35 fn deref(&self) -> &Self::Target {
36 self.0.as_ref()
37 }
38}
39
40impl Display for Bytes {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 write!(f, "{}", String::from_utf8_lossy(self.0.as_ref()))
43 }
44}
45
46impl Borrow<[u8]> for Bytes {
47 fn borrow(&self) -> &[u8] {
48 self.0.as_ref()
49 }
50}
51
52impl PartialEq<Bytes> for [u8] {
54 fn eq(&self, other: &Bytes) -> bool {
55 self == other.0.as_ref()
56 }
57}
58
59impl PartialEq<[u8]> for Bytes {
60 fn eq(&self, other: &[u8]) -> bool {
61 self.0.as_ref() == other
62 }
63}
64
65impl PartialEq<Bytes> for &[u8] {
66 fn eq(&self, other: &Bytes) -> bool {
67 *self == other.0.as_ref()
68 }
69}
70
71impl PartialEq<&[u8]> for Bytes {
72 fn eq(&self, other: &&[u8]) -> bool {
73 self.0.as_ref() == *other
74 }
75}
76
77impl<const N: usize> PartialEq<[u8; N]> for Bytes {
78 fn eq(&self, other: &[u8; N]) -> bool {
79 self.0.as_ref() == other
80 }
81}
82
83impl<const N: usize> PartialEq<Bytes> for [u8; N] {
84 fn eq(&self, other: &Bytes) -> bool {
85 self == other.0.as_ref()
86 }
87}
88
89impl<const N: usize> PartialEq<&[u8; N]> for Bytes {
90 fn eq(&self, other: &&[u8; N]) -> bool {
91 self.0.as_ref() == *other
92 }
93}
94impl<const N: usize> PartialEq<Bytes> for &[u8; N] {
95 fn eq(&self, other: &Bytes) -> bool {
96 *self == other.0.as_ref()
97 }
98}
99
100impl PartialEq<str> for Bytes {
101 fn eq(&self, other: &str) -> bool {
102 match self.to_str() {
103 Ok(s) => s == other,
104 Err(_) => false,
105 }
106 }
107}
108
109impl PartialEq<&str> for Bytes {
110 fn eq(&self, other: &&str) -> bool {
111 match self.to_str() {
112 Ok(s) => s == *other,
113 Err(_) => false,
114 }
115 }
116}
117
118impl PartialEq<Bytes> for str {
119 fn eq(&self, other: &Bytes) -> bool {
120 self.as_bytes() == other.0.as_ref()
121 }
122}
123impl PartialEq<Bytes> for &str {
124 fn eq(&self, other: &Bytes) -> bool {
125 self.as_bytes() == other.0.as_ref()
126 }
127}
128
129impl From<Box<[u8]>> for Bytes {
133 fn from(value: Box<[u8]>) -> Self {
134 Self(value)
135 }
136}
137
138impl From<&[u8]> for Bytes {
140 fn from(value: &[u8]) -> Self {
141 Self(value.to_vec().into_boxed_slice())
142 }
143}
144
145impl<const N: usize> From<&[u8; N]> for Bytes {
147 fn from(value: &[u8; N]) -> Self {
148 Self(Box::new(*value))
149 }
150}
151
152impl From<Vec<u8>> for Bytes {
156 fn from(value: Vec<u8>) -> Self {
157 Self(value.into_boxed_slice())
158 }
159}
160
161impl From<&str> for Bytes {
165 fn from(value: &str) -> Self {
166 Self(value.as_bytes().into())
167 }
168}
169
170#[cfg(test)]
173mod tests {
174 use super::*;
175 use std::collections::HashSet;
176
177 #[test]
178 fn test_display_valid_utf8() {
179 let s = "valid";
180 let b = Bytes::from(s);
181 assert_eq!(format!("{b}"), s);
182 }
183
184 #[test]
185 fn test_display_invalid_utf8() {
186 let b = Bytes::from(vec![0x48, 0xFF, 0x6c, 0x6c, 0x6f]);
187 assert_eq!(format!("{b}"), "H�llo");
188 }
189
190 #[test]
191 fn bytes_from_string_slice_roundtrip() {
192 let original = "Hello, http-wasm!";
193 let bytes = Bytes::from(original);
194 assert_eq!(bytes.to_str().unwrap(), original);
195 }
196
197 #[test]
198 fn bytes_from_byte_slice_roundtrip() {
199 let original: &[u8] = b"binary data \x00\x01\x02";
200 let bytes = Bytes::from(original);
201 assert_eq!(&bytes, original);
202 }
203
204 #[test]
205 fn bytes_from_vec_roundtrip() {
206 let original = vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]; let bytes = Bytes::from(original.clone());
208 assert_eq!(&bytes, original.as_slice());
209 }
210
211 #[test]
212 fn bytes_from_boxed_slice() {
213 let boxed: Box<[u8]> = vec![1, 2, 3, 4, 5].into_boxed_slice();
214 let bytes = Bytes::from(boxed.clone());
215 assert_eq!(&bytes, boxed.as_ref());
216 }
217
218 #[test]
219 fn bytes_equality() {
220 let a = Bytes::from("test");
221 let b = Bytes::from("test");
222 let c = Bytes::from("different");
223
224 assert_eq!(a, b);
225 assert_ne!(a, c);
226 }
227
228 #[test]
229 fn bytes_clone() {
230 let original = Bytes::from("clone me");
231 let cloned = original.clone();
232 assert_eq!(original, cloned);
233 }
234
235 #[test]
236 fn bytes_display() {
237 let bytes = Bytes::from("display test");
238 assert_eq!(format!("{}", bytes), "display test");
239 }
240
241 #[test]
242 fn bytes_empty() {
243 let empty = Bytes::from("");
244 assert!(empty.is_empty());
245 assert_eq!(empty.len(), 0);
246 }
247
248 #[test]
249 fn bytes_deref_to_slice() {
250 let bytes = Bytes::from("deref");
251 let slice: &[u8] = &bytes;
252 assert_eq!(slice, b"deref");
253 }
254
255 #[test]
256 fn bytes_hash_consistency() {
257 let a = Bytes::from("hash me");
258 let b = Bytes::from("hash me");
259
260 let mut set = HashSet::new();
261 set.insert(a.clone());
262
263 assert!(set.contains(&b));
264 assert_eq!(set.len(), 1);
265 }
266
267 #[test]
268 fn bytes_invalid_utf8_to_str() {
269 let invalid = Bytes::from(vec![0xFF, 0xFE]);
270 assert!(invalid.to_str().is_err());
271 }
272
273 #[test]
274 fn bytes_display_invalid_utf8() {
275 let invalid = Bytes::from(vec![0xFF, 0xFE]);
277 let displayed = format!("{}", invalid);
278 assert!(!displayed.is_empty());
280 }
281
282 #[test]
283 fn slice_eq_bytes() {
284 let slice: &[u8] = &vec![1, 2, 3, 4][..];
285 let bytes = Bytes::from(vec![1, 2, 3, 4]);
286 assert_eq!(slice, bytes);
287 assert_eq!(&*slice, &bytes);
288
289 assert!(bytes.eq(slice));
290 assert!(bytes.eq(&slice));
291 assert!(&bytes.eq(slice));
292 assert!(slice.eq(&bytes));
293 }
294
295 #[test]
296 fn array_slice_eq_bytes() {
297 let arr: &[u8; 4] = &[1, 2, 3, 4];
298 let bytes = Bytes::from(vec![1, 2, 3, 4]);
299 assert!(bytes.eq(&arr));
300 assert!(&bytes.eq(&arr));
301 assert!(arr.eq(&bytes));
302 assert_eq!(arr, bytes);
303 }
304
305 #[test]
306 fn str_slice_eq_bytes() {
307 let str = "test";
308 let bytes = Bytes::from("test");
309 assert_eq!(str, bytes);
310 assert!(bytes.eq(str));
311 assert!(&bytes.eq(str));
312 assert!(str.eq(&bytes));
313 }
314
315 #[test]
316 fn bytes_partial_str_invalid_bytes() {
317 let a = "test";
318 let b = Bytes::from(vec![0xFF, 0xFE]);
319
320 assert!(!b.eq(a));
321 assert!(!b.eq(&a));
322 assert!(!a.eq(&b));
323 }
324
325 #[test]
326 fn bytes_borrow() {
327 let a = b"test";
328 let b = Bytes::from(a);
329 let set: HashSet<Bytes> = HashSet::from([Bytes::from(a)]);
330 assert!(set.contains(&b));
331
332 assert_eq!(set.get(&b[..]), Some(&b));
333 assert_eq!(set.get(&b), Some(&b));
334 }
335}