1use crate::{PixelsError, Result};
14
15pub trait Source: Send {
20 fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
29
30 fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
38 let wanted = buf.len();
39 let mut filled = 0;
40 while filled < wanted {
41 let Some(rest) = buf.get_mut(filled..) else {
42 break;
43 };
44 match self.read(rest)? {
45 0 => {
46 return Err(PixelsError::malformed(
47 "stream",
48 format!("stream ended after {filled} of {wanted} expected bytes"),
49 ));
50 }
51 n => filled += n,
52 }
53 }
54 Ok(())
55 }
56}
57
58pub trait Sink: Send {
60 fn write_all(&mut self, buf: &[u8]) -> Result<()>;
66
67 fn flush(&mut self) -> Result<()>;
73}
74
75impl<R: std::io::Read + Send> Source for R {
76 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
77 loop {
78 return match std::io::Read::read(self, buf) {
79 Ok(n) => Ok(n),
80 Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
81 Err(e) => Err(PixelsError::io("reading from source", e)),
82 };
83 }
84 }
85}
86
87impl<W: std::io::Write + Send> Sink for W {
88 fn write_all(&mut self, buf: &[u8]) -> Result<()> {
89 std::io::Write::write_all(self, buf).map_err(|e| PixelsError::io("writing to sink", e))
90 }
91
92 fn flush(&mut self) -> Result<()> {
93 std::io::Write::flush(self).map_err(|e| PixelsError::io("flushing sink", e))
94 }
95}
96
97#[derive(Debug)]
105pub struct Prefixed<S: Source> {
106 prefix: Vec<u8>,
107 consumed: usize,
109 rest: S,
110}
111
112impl<S: Source> Prefixed<S> {
113 #[must_use]
115 pub const fn new(prefix: Vec<u8>, rest: S) -> Self {
116 Self {
117 prefix,
118 consumed: 0,
119 rest,
120 }
121 }
122}
123
124impl<S: Source> Source for Prefixed<S> {
125 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
126 let Some(remaining) = self.prefix.get(self.consumed..) else {
127 return self.rest.read(buf);
128 };
129 if remaining.is_empty() {
130 return self.rest.read(buf);
131 }
132 let take = remaining.len().min(buf.len());
136 let (Some(from), Some(into)) = (remaining.get(..take), buf.get_mut(..take)) else {
137 return Ok(0);
138 };
139 into.copy_from_slice(from);
140 self.consumed += take;
141 Ok(take)
142 }
143}
144
145#[cfg(test)]
146#[allow(
147 clippy::unwrap_used,
148 clippy::indexing_slicing,
149 reason = "tests operate on known-good values and assert shapes directly"
150)]
151mod tests {
152 use super::*;
153 use crate::ErrorCode;
154
155 struct Trickle {
158 data: Vec<u8>,
159 pos: usize,
160 chunk: usize,
161 }
162
163 impl Source for Trickle {
164 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
165 let remaining = self.data.len() - self.pos;
166 let n = remaining.min(buf.len()).min(self.chunk);
167 buf[..n].copy_from_slice(&self.data[self.pos..self.pos + n]);
168 self.pos += n;
169 Ok(n)
170 }
171 }
172
173 #[test]
174 fn read_exact_reassembles_short_reads() {
175 let mut src = Trickle {
176 data: (0..10).collect(),
177 pos: 0,
178 chunk: 3,
179 };
180 let mut buf = [0_u8; 10];
181 src.read_exact(&mut buf).unwrap();
182 assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
183 }
184
185 #[test]
186 fn a_truncated_stream_is_malformed_not_an_io_error() {
187 let mut src = Trickle {
188 data: vec![1, 2, 3],
189 pos: 0,
190 chunk: 2,
191 };
192 let mut buf = [0_u8; 8];
193 let err = src.read_exact(&mut buf).unwrap_err();
194 assert_eq!(err.code(), ErrorCode::Malformed);
195 assert!(err.to_string().contains("3 of 8"), "{err}");
196 }
197
198 #[test]
199 fn slices_and_vecs_work_without_adapters() {
200 let mut src: &[u8] = b"hello";
201 let mut buf = [0_u8; 5];
202 src.read_exact(&mut buf).unwrap();
203 assert_eq!(&buf, b"hello");
204
205 let mut sink: Vec<u8> = Vec::new();
206 sink.write_all(b"out").unwrap();
207 sink.flush().unwrap();
208 assert_eq!(sink, b"out");
209 }
210
211 #[test]
212 fn read_exact_of_nothing_succeeds() {
213 let mut src: &[u8] = b"";
214 src.read_exact(&mut []).unwrap();
215 }
216
217 #[test]
218 fn sink_errors_are_reported_as_io() {
219 struct Broken;
220 impl std::io::Write for Broken {
221 fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
222 Err(std::io::Error::other("disk full"))
223 }
224 fn flush(&mut self) -> std::io::Result<()> {
225 Err(std::io::Error::other("disk full"))
226 }
227 }
228 let err = Sink::write_all(&mut Broken, b"x").unwrap_err();
229 assert_eq!(err.code(), ErrorCode::Io);
230 assert_eq!(Sink::flush(&mut Broken).unwrap_err().code(), ErrorCode::Io);
231 }
232
233 #[test]
234 fn a_prefixed_source_replays_then_delegates() {
235 let mut source = Prefixed::new(vec![1, 2, 3], &b"456"[..]);
236 let mut all = Vec::new();
237 let mut buf = [0_u8; 2];
238 loop {
239 match source.read(&mut buf).unwrap() {
240 0 => break,
241 n => all.extend_from_slice(&buf[..n]),
242 }
243 }
244 assert_eq!(all, vec![1, 2, 3, b'4', b'5', b'6']);
245 }
246
247 #[test]
248 fn a_prefixed_source_never_mixes_the_prefix_into_one_read() {
249 let mut source = Prefixed::new(vec![9, 9], &b"xyz"[..]);
252 let mut buf = [0_u8; 16];
253 assert_eq!(source.read(&mut buf).unwrap(), 2);
254 assert_eq!(&buf[..2], &[9, 9]);
255 assert_eq!(source.read(&mut buf).unwrap(), 3);
256 assert_eq!(&buf[..3], b"xyz");
257 assert_eq!(source.read(&mut buf).unwrap(), 0);
258 }
259
260 #[test]
261 fn an_empty_prefix_is_a_pass_through() {
262 let mut source = Prefixed::new(Vec::new(), &b"data"[..]);
263 let mut buf = [0_u8; 8];
264 assert_eq!(source.read(&mut buf).unwrap(), 4);
265 assert_eq!(&buf[..4], b"data");
266 }
267
268 #[test]
269 fn read_exact_spans_the_prefix_boundary() {
270 let mut source = Prefixed::new(vec![0xDE, 0xAD], &b"\xBE\xEF"[..]);
273 let mut buf = [0_u8; 4];
274 source.read_exact(&mut buf).unwrap();
275 assert_eq!(buf, [0xDE, 0xAD, 0xBE, 0xEF]);
276 }
277}