1 //! Asynchronous `pxar` format handling.
5 #[cfg(feature = "tokio-fs")]
8 use crate::decoder
::{self, Contents, SeqRead}
;
11 /// Asynchronous `pxar` decoder.
13 /// This is the `async` version of the `pxar` decoder.
15 pub struct Decoder
<T
> {
16 inner
: decoder
::DecoderImpl
<T
>,
19 #[cfg(feature = "tokio-io")]
20 impl<T
: tokio
::io
::AsyncRead
> Decoder
<TokioReader
<T
>> {
21 /// Decode a `pxar` archive from a `tokio::io::AsyncRead` input.
23 pub async
fn from_tokio(input
: T
) -> io
::Result
<Self> {
24 Decoder
::new(TokioReader
::new(input
)).await
28 #[cfg(feature = "tokio-fs")]
29 impl Decoder
<TokioReader
<tokio
::fs
::File
>> {
30 /// Decode a `pxar` archive from a `tokio::io::AsyncRead` input.
32 pub async
fn open
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<Self> {
33 Decoder
::from_tokio(tokio
::fs
::File
::open(path
.as_ref()).await?
).await
37 impl<T
: SeqRead
> Decoder
<T
> {
38 /// Create an async decoder from an input implementing our internal read interface.
39 pub async
fn new(input
: T
) -> io
::Result
<Self> {
41 inner
: decoder
::DecoderImpl
::new(input
).await?
,
45 /// Internal helper for `Accessor`. In this case we have the low-level state machine, and the
46 /// layer "above" the `Accessor` propagates the actual type (sync vs async).
47 pub(crate) fn from_impl(inner
: decoder
::DecoderImpl
<T
>) -> Self {
51 // I would normally agree with clippy, but this is async and we can at most implement Stream,
52 // which we do with feature flags...
53 #[allow(clippy::should_implement_trait)]
54 /// If this is a directory entry, get the next item inside the directory.
55 pub async
fn next(&mut self) -> Option
<io
::Result
<Entry
>> {
56 self.inner
.next_do().await
.transpose()
59 /// Get a reader for the contents of the current entry, if the entry has contents.
60 pub fn contents(&mut self) -> Option
<Contents
<T
>> {
61 self.inner
.content_reader()
64 /// Get the size of the current contents, if the entry has contents.
65 pub fn content_size(&self) -> Option
<u64> {
66 self.inner
.content_size()
69 /// Include goodbye tables in iteration.
70 pub fn enable_goodbye_entries(&mut self, on
: bool
) {
71 self.inner
.with_goodbye_tables
= on
;
75 #[cfg(feature = "tokio-io")]
77 use crate::decoder
::{Contents, SeqRead}
;
80 use std
::task
::{Context, Poll}
;
82 /// Read adapter for `futures::io::AsyncRead`
83 pub struct TokioReader
<T
> {
87 impl<T
: tokio
::io
::AsyncRead
> TokioReader
<T
> {
88 pub fn new(inner
: T
) -> Self {
93 impl<T
: tokio
::io
::AsyncRead
> crate::decoder
::SeqRead
for TokioReader
<T
> {
98 ) -> Poll
<io
::Result
<usize>> {
99 let mut read_buf
= tokio
::io
::ReadBuf
::new(buf
);
101 self.map_unchecked_mut(|this
| &mut this
.inner
)
102 .poll_read(cx
, &mut read_buf
)
103 .map_ok(|_
| read_buf
.filled().len())
108 impl<'a
, T
: crate::decoder
::SeqRead
> tokio
::io
::AsyncRead
for Contents
<'a
, T
> {
110 self: Pin
<&mut Self>,
111 cx
: &mut Context
<'_
>,
112 buf
: &mut tokio
::io
::ReadBuf
<'_
>,
113 ) -> Poll
<io
::Result
<()>> {
115 // Safety: poll_seq_read will *probably* only write to the buffer, so we don't
116 // initialize it first, instead we treat is a &[u8] immediately and uphold the
117 // ReadBuf invariants in the conditional below.
119 &mut *(buf
.unfilled_mut() as *mut [std
::mem
::MaybeUninit
<u8>] as *mut [u8]);
120 let result
= self.poll_seq_read(cx
, write_buf
);
121 if let Poll
::Ready(Ok(n
)) = result
{
122 // if we've written data, advance both initialized and filled bytes cursor
126 result
.map(|_
| Ok(()))
132 #[cfg(feature = "tokio-io")]
133 use tok
::TokioReader
;