1use crate::{Error, ErrorKind, Result};
2use std::future::Future;
3use std::pin::Pin;
4
5pub type IoFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T>> + 'a>>;
7
8pub trait ByteSource {
10 fn len(&self) -> Option<u64>;
11
12 fn is_empty(&self) -> Option<bool> {
13 self.len().map(|length| length == 0)
14 }
15
16 fn read_at<'a>(&'a self, offset: u64, destination: &'a mut [u8]) -> IoFuture<'a, usize>;
17}
18
19pub trait ByteSink {
30 fn position(&self) -> u64;
31 fn is_seekable(&self) -> bool {
32 true
33 }
34 fn write<'a>(&'a mut self, bytes: &'a [u8]) -> IoFuture<'a, ()>;
35 fn seek<'a>(&'a mut self, position: u64) -> IoFuture<'a, ()>;
36 fn flush<'a>(&'a mut self) -> IoFuture<'a, ()> {
37 Box::pin(async { Ok(()) })
38 }
39}
40
41#[derive(Clone, Debug, Default, Eq, PartialEq)]
43pub struct MemorySource {
44 bytes: Vec<u8>,
45}
46
47impl MemorySource {
48 pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
49 Self {
50 bytes: bytes.into(),
51 }
52 }
53
54 pub fn as_slice(&self) -> &[u8] {
55 &self.bytes
56 }
57}
58
59impl ByteSource for MemorySource {
60 fn len(&self) -> Option<u64> {
61 u64::try_from(self.bytes.len()).ok()
62 }
63
64 fn read_at<'a>(&'a self, offset: u64, destination: &'a mut [u8]) -> IoFuture<'a, usize> {
65 Box::pin(async move {
66 let offset = usize::try_from(offset)
67 .map_err(|_| Error::new(ErrorKind::InvalidInput, "read offset is too large"))?;
68 if offset > self.bytes.len() {
69 return Err(Error::new(
70 ErrorKind::InvalidInput,
71 "read offset is beyond the source",
72 ));
73 }
74 let length = destination.len().min(self.bytes.len() - offset);
75 destination[..length].copy_from_slice(&self.bytes[offset..offset + length]);
76 Ok(length)
77 })
78 }
79}
80
81#[derive(Clone, Debug, Default, Eq, PartialEq)]
83pub struct MemorySink {
84 bytes: Vec<u8>,
85 position: u64,
86}
87
88impl MemorySink {
89 pub fn new() -> Self {
90 Self::default()
91 }
92
93 pub fn into_inner(self) -> Vec<u8> {
94 self.bytes
95 }
96
97 pub fn as_slice(&self) -> &[u8] {
98 &self.bytes
99 }
100}
101
102impl ByteSink for MemorySink {
103 fn position(&self) -> u64 {
104 self.position
105 }
106
107 fn write<'a>(&'a mut self, bytes: &'a [u8]) -> IoFuture<'a, ()> {
108 Box::pin(async move {
109 let position = usize::try_from(self.position)
110 .map_err(|_| Error::new(ErrorKind::ResourceLimit, "sink position is too large"))?;
111 let end = position
112 .checked_add(bytes.len())
113 .ok_or_else(|| Error::new(ErrorKind::ResourceLimit, "sink allocation overflow"))?;
114 if end > self.bytes.len() {
115 self.bytes.resize(end, 0);
116 }
117 self.bytes[position..end].copy_from_slice(bytes);
118 self.position = u64::try_from(end).map_err(|_| {
119 Error::new(
120 ErrorKind::ResourceLimit,
121 "sink position cannot be represented",
122 )
123 })?;
124 Ok(())
125 })
126 }
127
128 fn seek<'a>(&'a mut self, position: u64) -> IoFuture<'a, ()> {
129 Box::pin(async move {
130 usize::try_from(position)
131 .map_err(|_| Error::new(ErrorKind::InvalidInput, "seek position is too large"))?;
132 self.position = position;
133 Ok(())
134 })
135 }
136}
137
138#[doc(hidden)]
142#[derive(Clone, Debug, Default, Eq, PartialEq)]
143pub struct NonSeekableSink {
144 bytes: Vec<u8>,
145}
146
147impl ByteSink for NonSeekableSink {
148 fn position(&self) -> u64 {
149 self.bytes.len() as u64
150 }
151
152 fn is_seekable(&self) -> bool {
153 false
154 }
155
156 fn write<'a>(&'a mut self, bytes: &'a [u8]) -> IoFuture<'a, ()> {
157 Box::pin(async move {
158 self.bytes.extend_from_slice(bytes);
159 Ok(())
160 })
161 }
162
163 fn seek<'a>(&'a mut self, _position: u64) -> IoFuture<'a, ()> {
164 Box::pin(async move {
165 Err(Error::new(
166 ErrorKind::Unsupported,
167 "this sink does not support seeking",
168 ))
169 })
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use std::task::{Context, Poll, Waker};
177
178 fn ready<T>(mut future: IoFuture<'_, T>) -> Result<T> {
179 let waker = Waker::noop();
180 let mut context = Context::from_waker(waker);
181 match future.as_mut().poll(&mut context) {
182 Poll::Ready(result) => result,
183 Poll::Pending => panic!("memory I/O unexpectedly returned a pending future"),
184 }
185 }
186
187 #[test]
188 fn memory_source_reads_partially_at_end_of_source() {
189 let source = MemorySource::new(b"abcdef".to_vec());
190 let mut destination = [0_u8; 4];
191 assert_eq!(ready(source.read_at(4, &mut destination)).unwrap(), 2);
192 assert_eq!(&destination[..2], b"ef");
193 }
194
195 #[test]
196 fn memory_source_rejects_offsets_beyond_end() {
197 let source = MemorySource::new(b"abc".to_vec());
198 let mut destination = [0_u8; 1];
199 let error = ready(source.read_at(4, &mut destination)).unwrap_err();
200 assert_eq!(error.kind(), ErrorKind::InvalidInput);
201 }
202
203 #[test]
204 fn memory_sink_seeks_overwrites_and_zero_fills() {
205 let mut sink = MemorySink::new();
206 ready(sink.write(b"abc")).unwrap();
207 ready(sink.seek(1)).unwrap();
208 ready(sink.write(b"Z")).unwrap();
209 ready(sink.seek(5)).unwrap();
210 ready(sink.write(b"!")).unwrap();
211 assert_eq!(sink.as_slice(), b"aZc\0\0!");
212 }
213
214 #[test]
215 fn non_seekable_sink_writes_but_rejects_seek() {
216 let mut sink = NonSeekableSink::default();
217 assert!(!sink.is_seekable());
218 ready(sink.write(b"abc")).unwrap();
219 assert_eq!(sink.bytes, b"abc");
220 let error = ready(sink.seek(0)).unwrap_err();
221 assert_eq!(error.kind(), ErrorKind::Unsupported);
222 }
223}