) -> Poll<io::Result<usize>>;
}
-/// We do not want to bother with actual polling, so we implement `async fn` variants of the above
-/// on `dyn ReadAt`.
-///
-/// The reason why this is not an internal `ReadAtExt` trait like `AsyncReadExt` is simply that
-/// we'd then need to define all the `Future` types they return manually and explicitly. Since we
-/// have no use for them, all we want is the ability to use `async fn`...
-///
-/// The downside is that we need some `(&mut self.input as &mut dyn ReadAt)` casts in the
-/// decoder's code, but that's fine.
-impl<'a> dyn ReadAt + 'a {
- /// awaitable version of `poll_read_at`.
- async fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
- poll_fn(|cx| unsafe { Pin::new_unchecked(self).poll_read_at(cx, buf, offset) }).await
- }
-
- /// `read_exact_at` - since that's what we _actually_ want most of the time.
- async fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
- while !buf.is_empty() {
- match self.read_at(buf, offset).await? {
- 0 => io_bail!("unexpected EOF"),
- got => {
- buf = &mut buf[got..];
- offset += got as u64;
- }
+/// awaitable version of `poll_read_at`.
+async fn read_at<T>(input: &T, buf: &mut [u8], offset: u64) -> io::Result<usize>
+where
+ T: ReadAt + ?Sized,
+{
+ poll_fn(|cx| unsafe { Pin::new_unchecked(input).poll_read_at(cx, buf, offset) }).await
+}
+
+/// `read_exact_at` - since that's what we _actually_ want most of the time.
+async fn read_exact_at<T>(input: &T, mut buf: &mut [u8], mut offset: u64) -> io::Result<()>
+where
+ T: ReadAt + ?Sized,
+{
+ while !buf.is_empty() {
+ match read_at(input, buf, offset).await? {
+ 0 => io_bail!("unexpected EOF"),
+ got => {
+ buf = &mut buf[got..];
+ offset += got as u64;
}
}
- Ok(())
}
+ Ok(())
+}
- /// Helper to read into an `Endian`-implementing `struct`.
- async fn read_entry_at<T: Endian>(&self, offset: u64) -> io::Result<T> {
- let mut data = MaybeUninit::<T>::uninit();
- let buf =
- unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut u8, size_of::<T>()) };
- self.read_exact_at(buf, offset).await?;
- Ok(unsafe { data.assume_init().from_le() })
- }
+/// Helper to read into an `Endian`-implementing `struct`.
+async fn read_entry_at<T, E: Endian>(input: &T, offset: u64) -> io::Result<E>
+where
+ T: ReadAt + ?Sized,
+{
+ let mut data = MaybeUninit::<E>::uninit();
+ let buf =
+ unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut u8, size_of::<E>()) };
+ read_exact_at(input, buf, offset).await?;
+ Ok(unsafe { data.assume_init().from_le() })
+}
- /// Helper to read into an allocated byte vector.
- async fn read_exact_data_at(&self, size: usize, offset: u64) -> io::Result<Vec<u8>> {
- let mut data = util::vec_new(size);
- self.read_exact_at(&mut data[..], offset).await?;
- Ok(data)
- }
+/// Helper to read into an allocated byte vector.
+async fn read_exact_data_at<T>(input: &T, size: usize, offset: u64) -> io::Result<Vec<u8>>
+where
+ T: ReadAt + ?Sized,
+{
+ let mut data = util::vec_new(size);
+ read_exact_at(input, &mut data[..], offset).await?;
+ Ok(data)
}
/// Allow using trait objects for `T: ReadAt`
data.as_mut_ptr() as *mut u8,
len * size_of::<GoodbyeItem>(),
);
- (&self.input as &dyn ReadAt)
- .read_exact_at(slice, self.table_offset())
- .await?;
+ read_exact_at(&self.input, slice, self.table_offset()).await?;
drop(slice);
}
Ok(Arc::from(data))
}
/// Read the goodbye tail and perform some sanity checks.
- async fn read_tail_entry(input: &'_ dyn ReadAt, end_offset: u64) -> io::Result<GoodbyeItem> {
+ async fn read_tail_entry(input: &T, end_offset: u64) -> io::Result<GoodbyeItem> {
if end_offset < (size_of::<GoodbyeItem>() as u64) {
io_bail!("goodbye tail does not fit");
}
let tail_offset = end_offset - (size_of::<GoodbyeItem>() as u64);
- let tail: GoodbyeItem = input.read_entry_at(tail_offset).await?;
+ let tail: GoodbyeItem = read_entry_at(input, tail_offset).await?;
if tail.hash != format::PXAR_GOODBYE_TAIL_MARKER {
io_bail!("no goodbye tail marker found");
}
async fn read_filename_entry(&self, file_ofs: u64) -> io::Result<(PathBuf, u64)> {
- let head: format::Header = (&self.input as &dyn ReadAt).read_entry_at(file_ofs).await?;
+ let head: format::Header = read_entry_at(&self.input, file_ofs).await?;
if head.htype != format::PXAR_FILENAME {
io_bail!("expected PXAR_FILENAME header, found: {:x}", head.htype);
}
- let mut path = (&self.input as &dyn ReadAt)
- .read_exact_data_at(
- head.content_size() as usize,
- file_ofs + (size_of_val(&head) as u64),
- )
- .await?;
+ let mut path = read_exact_data_at(
+ &self.input,
+ head.content_size() as usize,
+ file_ofs + (size_of_val(&head) as u64),
+ )
+ .await?;
if path.pop() != Some(0) {
io_bail!("invalid file name (missing terminating zero)");
buf = &mut buf[..(remaining as usize)];
}
- (&self.input as &dyn ReadAt)
- .read_at(buf, self.range.start + offset)
- .await
+ read_at(&self.input, buf, self.range.start + offset).await
}
}