1use crate::error::Result;
13use bytes::Bytes;
14use futures::Stream;
15use std::fmt;
16use std::pin::Pin;
17
18pub type ByteStream<'a> = Pin<Box<dyn Stream<Item = Result<Bytes>> + Send + 'a>>;
21
22#[derive(Clone, Copy)]
27pub struct MmapView<'a>(&'a [u8]);
28
29impl<'a> MmapView<'a> {
30 #[must_use]
32 pub fn new(bytes: &'a [u8]) -> Self {
33 Self(bytes)
34 }
35
36 #[must_use]
38 pub fn as_slice(&self) -> &'a [u8] {
39 self.0
40 }
41}
42
43impl fmt::Debug for MmapView<'_> {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 f.debug_struct("MmapView")
46 .field("len", &self.0.len())
47 .finish()
48 }
49}
50
51impl AsRef<[u8]> for MmapView<'_> {
52 fn as_ref(&self) -> &[u8] {
53 self.0
54 }
55}
56
57pub enum DocPayload<'a> {
59 Borrowed(&'a [u8]),
61 Mapped(MmapView<'a>),
63 Owned(Bytes),
65 Stream(ByteStream<'a>),
67}
68
69impl DocPayload<'_> {
70 #[must_use]
75 pub fn as_slice(&self) -> Option<&[u8]> {
76 match self {
77 Self::Borrowed(b) => Some(b),
78 Self::Mapped(m) => Some(m.as_slice()),
79 Self::Owned(b) => Some(b),
80 Self::Stream(_) => None,
81 }
82 }
83
84 #[must_use]
86 pub fn len(&self) -> Option<usize> {
87 self.as_slice().map(<[u8]>::len)
88 }
89
90 #[must_use]
92 pub fn is_empty(&self) -> Option<bool> {
93 self.as_slice().map(<[u8]>::is_empty)
94 }
95
96 pub async fn into_bytes(self) -> Result<Bytes> {
98 match self {
99 Self::Borrowed(b) => Ok(Bytes::copy_from_slice(b)),
100 Self::Mapped(m) => Ok(Bytes::copy_from_slice(m.as_slice())),
101 Self::Owned(b) => Ok(b),
102 Self::Stream(mut s) => {
103 use futures::StreamExt;
104 let mut buf = Vec::new();
105 while let Some(chunk) = s.next().await {
106 buf.extend_from_slice(&chunk?);
107 }
108 Ok(Bytes::from(buf))
109 }
110 }
111 }
112}
113
114impl fmt::Debug for DocPayload<'_> {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 match self {
117 Self::Borrowed(b) => f.debug_tuple("Borrowed").field(&b.len()).finish(),
118 Self::Mapped(m) => f.debug_tuple("Mapped").field(&m.as_slice().len()).finish(),
119 Self::Owned(b) => f.debug_tuple("Owned").field(&b.len()).finish(),
120 Self::Stream(_) => f.write_str("Stream(..)"),
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn borrowed_and_owned_expose_slices() {
131 let data = b"hello world";
132 let borrowed = DocPayload::Borrowed(data);
133 assert_eq!(borrowed.as_slice(), Some(&data[..]));
134 assert_eq!(borrowed.len(), Some(11));
135 assert_eq!(borrowed.is_empty(), Some(false));
136
137 let owned = DocPayload::Owned(Bytes::from_static(data));
138 assert_eq!(owned.as_slice(), Some(&data[..]));
139 }
140
141 #[test]
142 fn mapped_view_roundtrips() {
143 let data = [1u8, 2, 3, 4];
144 let view = MmapView::new(&data);
145 assert_eq!(view.as_slice(), &data);
146 assert_eq!(view.as_ref(), &data);
147 }
148
149 #[test]
150 fn stream_has_no_in_memory_slice() {
151 let s: ByteStream<'_> = Box::pin(futures::stream::empty());
152 let payload = DocPayload::Stream(s);
153 assert_eq!(payload.as_slice(), None);
154 assert_eq!(payload.len(), None);
155 }
156
157 #[tokio::test]
158 async fn into_bytes_drains_a_stream() {
159 let chunks = vec![
160 Ok(Bytes::from_static(b"foo")),
161 Ok(Bytes::from_static(b"bar")),
162 ];
163 let s: ByteStream<'_> = Box::pin(futures::stream::iter(chunks));
164 let bytes = DocPayload::Stream(s).into_bytes().await.unwrap();
165 assert_eq!(&bytes[..], b"foobar");
166 }
167
168 #[tokio::test]
169 async fn into_bytes_on_borrowed_copies() {
170 let bytes = DocPayload::Borrowed(b"abc").into_bytes().await.unwrap();
171 assert_eq!(&bytes[..], b"abc");
172 }
173}