turbo_tasks_bytes/
bytes.rs

1use std::{
2    ops::Deref,
3    str::{Utf8Error, from_utf8},
4};
5
6use anyhow::Result;
7use bytes::Bytes as CBytes;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10/// Bytes is a thin wrapper around [bytes::Bytes], implementing easy
11/// conversion to/from, ser/de support, and Vc containers.
12#[derive(Clone, Debug, Default)]
13#[turbo_tasks::value(transparent, serialization = "custom")]
14pub struct Bytes(#[turbo_tasks(trace_ignore)] CBytes);
15
16impl Bytes {
17    pub fn to_str(&self) -> Result<&'_ str, Utf8Error> {
18        from_utf8(&self.0)
19    }
20}
21
22impl Serialize for Bytes {
23    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
24        serde_bytes::Bytes::new(&self.0).serialize(serializer)
25    }
26}
27
28impl<'de> Deserialize<'de> for Bytes {
29    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
30        let bytes = serde_bytes::ByteBuf::deserialize(deserializer)?;
31        Ok(Bytes(bytes.into_vec().into()))
32    }
33}
34
35impl Deref for Bytes {
36    type Target = CBytes;
37    fn deref(&self) -> &Self::Target {
38        &self.0
39    }
40}
41
42/// Types that implement From<X> for Bytes {}
43/// Unfortunately, we cannot just use the more generic `Into<Bytes>` without
44/// running afoul of the `From<X> for X` base case, causing conflicting impls.
45pub trait IntoBytes: Into<CBytes> {}
46impl IntoBytes for &'static [u8] {}
47impl IntoBytes for &'static str {}
48impl IntoBytes for Vec<u8> {}
49impl IntoBytes for Box<[u8]> {}
50impl IntoBytes for String {}
51
52impl<T: IntoBytes> From<T> for Bytes {
53    fn from(value: T) -> Self {
54        Bytes(value.into())
55    }
56}
57
58impl From<CBytes> for Bytes {
59    fn from(value: CBytes) -> Self {
60        Bytes(value)
61    }
62}
63
64impl From<Bytes> for CBytes {
65    fn from(value: Bytes) -> Self {
66        value.0
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use bytes::Bytes as CBytes;
73    use serde_test::{Token, assert_tokens};
74
75    use super::Bytes;
76    impl PartialEq<&str> for Bytes {
77        fn eq(&self, other: &&str) -> bool {
78            self.0 == other
79        }
80    }
81
82    #[test]
83    fn into_bytes() {
84        let s = "foo".to_string();
85        assert_eq!(Bytes::from(b"foo" as &'static [u8]), "foo");
86        assert_eq!(Bytes::from("foo"), "foo");
87        assert_eq!(Bytes::from(s.as_bytes().to_vec()), "foo");
88        assert_eq!(Bytes::from(s.as_bytes().to_vec().into_boxed_slice()), "foo");
89        assert_eq!(Bytes::from(s), "foo");
90    }
91
92    #[test]
93    fn serde() {
94        let s = Bytes::from("test");
95        assert_tokens(&s, &[Token::Bytes(b"test")])
96    }
97
98    #[test]
99    fn from_into() {
100        let b = Bytes::from("foo");
101        let cb = CBytes::from("foo");
102        assert_eq!(Bytes::from(cb), "foo");
103        assert_eq!(CBytes::from(b), "foo");
104    }
105
106    #[test]
107    fn deref() {
108        let b = Bytes::from("foo");
109        assert_eq!(*b, CBytes::from("foo"));
110    }
111
112    #[test]
113    fn to_str() {
114        let cb = Bytes::from("foo");
115        assert_eq!(cb.to_str(), Ok("foo"));
116
117        let b = Bytes::from("💩".as_bytes()[0..3].to_vec());
118        assert!(b.to_str().is_err());
119    }
120}