1 //! Asynchronous `pxar` format handling.
6 use std
::task
::{Context, Poll}
;
8 use crate::encoder
::{self, SeqWrite}
;
12 // #[cfg(feature = "futures-io")]
13 // use crate::decoder::aio::FuturesReader;
14 // #[cfg(feature = "tokio-io")]
15 // use crate::decoder::aio::TokioReader;
17 /// Asynchronous `pxar` encoder.
19 /// This is the `async` version of the `pxar` encoder.
21 pub struct Encoder
<'a
, T
: SeqWrite
+ 'a
> {
22 inner
: encoder
::EncoderImpl
<'a
, T
>,
25 #[cfg(feature = "futures-io")]
26 impl<'a
, T
: futures
::io
::AsyncWrite
+ 'a
> Encoder
<'a
, FuturesWriter
<T
>> {
27 /// Encode a `pxar` archive into a `futures::io::AsyncWrite` output.
29 pub async
fn from_futures(
32 ) -> io
::Result
<Encoder
<'a
, FuturesWriter
<T
>>> {
33 Encoder
::new(FuturesWriter
::new(output
), metadata
).await
37 #[cfg(feature = "tokio-io")]
38 impl<'a
, T
: tokio
::io
::AsyncWrite
+ 'a
> Encoder
<'a
, TokioWriter
<T
>> {
39 /// Encode a `pxar` archive into a `tokio::io::AsyncWrite` output.
41 pub async
fn from_futures(
44 ) -> io
::Result
<Encoder
<'a
, TokioWriter
<T
>>> {
45 Encoder
::new(TokioWriter
::new(output
), metadata
).await
49 #[cfg(feature = "tokio-fs")]
50 impl<'a
> Encoder
<'a
, TokioWriter
<tokio
::fs
::File
>> {
51 /// Convenience shortcut for `File::create` followed by `Encoder::from_tokio`.
52 pub async
fn create
<'b
, P
: AsRef
<Path
>>(
54 metadata
: &'b Metadata
,
55 ) -> io
::Result
<Encoder
<'a
, TokioWriter
<tokio
::fs
::File
>>> {
57 TokioWriter
::new(tokio
::fs
::File
::create(path
.as_ref()).await?
),
64 impl<'a
, T
: SeqWrite
+ 'a
> Encoder
<'a
, T
> {
65 /// Create an asynchronous encoder for an output implementing our internal write interface.
66 pub async
fn new(output
: T
, metadata
: &Metadata
) -> io
::Result
<Encoder
<'a
, T
>> {
68 inner
: encoder
::EncoderImpl
::new(output
, metadata
).await?
,
72 /// Create a new regular file in the archive. This returns a `File` object to which the
73 /// contents have to be written out *completely*. Failing to do so will put the encoder into an
75 pub async
fn create_file
<'b
, P
: AsRef
<Path
>>(
80 ) -> io
::Result
<File
<'b
>>
87 .create_file(metadata
, file_name
.as_ref(), file_size
)
92 // /// Convenience shortcut to add a *regular* file by path including its contents to the archive.
93 // pub async fn add_file<P, F>(
95 // metadata: &Metadata,
98 // content: &mut dyn tokio::io::Read,
99 // ) -> io::Result<()>
104 // self.inner.add_file(
106 // file_name.as_ref(),
108 // content.as_async_reader(),
112 /// Create a new subdirectory. Note that the subdirectory has to be finished by calling the
113 /// `finish()` method, otherwise the entire archive will be in an error state.
114 pub async
fn create_directory
<'b
, P
: AsRef
<Path
>>(
118 ) -> io
::Result
<Encoder
<'b
, &'b
mut dyn SeqWrite
>>
125 .create_directory(file_name
.as_ref(), metadata
)
130 /// Finish this directory. This is mandatory, otherwise the `Drop` handler will `panic!`.
131 pub async
fn finish(self) -> io
::Result
<()> {
132 self.inner
.finish().await
135 /// Add a symbolic link to the archive.
136 pub async
fn add_symlink
<PF
: AsRef
<Path
>, PT
: AsRef
<Path
>>(
141 ) -> io
::Result
<()> {
143 .add_symlink(metadata
, file_name
.as_ref(), target
.as_ref())
147 /// Add a hard link to the archive.
148 pub async
fn add_hardlink
<PF
: AsRef
<Path
>, PT
: AsRef
<Path
>>(
153 ) -> io
::Result
<()> {
155 .add_hardlink(file_name
.as_ref(), target
.as_ref(), offset
)
159 /// Add a device node to the archive.
160 pub async
fn add_device
<P
: AsRef
<Path
>>(
164 device
: format
::Device
,
165 ) -> io
::Result
<()> {
167 .add_device(metadata
, file_name
.as_ref(), device
)
171 /// Add a device node to the archive.
172 pub async
fn add_fifo
<P
: AsRef
<Path
>>(
176 ) -> io
::Result
<()> {
177 self.inner
.add_fifo(metadata
, file_name
.as_ref()).await
180 /// Add a device node to the archive.
181 pub async
fn add_socket
<P
: AsRef
<Path
>>(
185 ) -> io
::Result
<()> {
186 self.inner
.add_socket(metadata
, file_name
.as_ref()).await
191 pub struct File
<'a
> {
192 inner
: encoder
::FileImpl
<'a
>,
195 #[cfg(feature = "futures-io")]
196 impl<'a
> futures
::io
::AsyncWrite
for File
<'a
> {
197 fn poll_write(self: Pin
<&mut Self>, cx
: &mut Context
, data
: &[u8]) -> Poll
<io
::Result
<usize>> {
198 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_write(cx
, data
)
201 fn poll_flush(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
202 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_flush(cx
)
205 fn poll_close(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
206 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_close(cx
)
210 #[cfg(feature = "tokio-io")]
211 impl<'a
> tokio
::io
::AsyncWrite
for File
<'a
> {
212 fn poll_write(self: Pin
<&mut Self>, cx
: &mut Context
, data
: &[u8]) -> Poll
<io
::Result
<usize>> {
213 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_write(cx
, data
)
216 fn poll_flush(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
217 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_flush(cx
)
220 fn poll_shutdown(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
221 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_close(cx
)
225 /// Pxar encoder write adapter for `futures::io::AsyncWrite`.
226 #[cfg(feature = "futures-io")]
230 use std
::task
::{Context, Poll}
;
232 use crate::encoder
::SeqWrite
;
234 pub struct FuturesWriter
<T
> {
239 impl<T
: futures
::io
::AsyncWrite
> FuturesWriter
<T
> {
240 pub fn new(inner
: T
) -> Self {
247 fn inner_mut(self: &mut Self) -> io
::Result
<Pin
<&mut T
>> {
251 .ok_or_else(|| io_format_err
!("write after close"))?
;
252 Ok(unsafe { Pin::new_unchecked(inner) }
)
255 fn inner(self: Pin
<&mut Self>) -> io
::Result
<Pin
<&mut T
>> {
256 unsafe { self.get_unchecked_mut() }
.inner_mut()
260 impl<T
: futures
::io
::AsyncWrite
> SeqWrite
for FuturesWriter
<T
> {
262 self: Pin
<&mut Self>,
265 ) -> Poll
<io
::Result
<usize>> {
266 let this
= unsafe { self.get_unchecked_mut() }
;
267 let got
= ready
!(this
.inner_mut()?
.poll_write(cx
, buf
))?
;
268 this
.position
+= got
as u64;
272 fn poll_position(self: Pin
<&mut Self>, _cx
: &mut Context
) -> Poll
<io
::Result
<u64>> {
273 Poll
::Ready(Ok(self.as_ref().position
))
276 fn poll_flush(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
277 self.inner()?
.poll_flush(cx
)
280 fn poll_close(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
281 let this
= unsafe { self.get_unchecked_mut() }
;
282 match this
.inner
.as_mut() {
283 None
=> return Poll
::Ready(Ok(())),
285 ready
!(unsafe { Pin::new_unchecked(inner).poll_close(cx) }
)?
;
294 pub use futures_writer
::FuturesWriter
;
296 /// Pxar encoder write adapter for `tokio::io::AsyncWrite`.
297 #[cfg(feature = "tokio-io")]
301 use std
::task
::{Context, Poll}
;
303 use crate::encoder
::SeqWrite
;
305 pub struct TokioWriter
<T
> {
310 impl<T
: tokio
::io
::AsyncWrite
> TokioWriter
<T
> {
311 pub fn new(inner
: T
) -> Self {
318 fn inner_mut(self: &mut Self) -> io
::Result
<Pin
<&mut T
>> {
322 .ok_or_else(|| io_format_err
!("write after close"))?
;
323 Ok(unsafe { Pin::new_unchecked(inner) }
)
326 fn inner(self: Pin
<&mut Self>) -> io
::Result
<Pin
<&mut T
>> {
327 unsafe { self.get_unchecked_mut() }
.inner_mut()
331 impl<T
: tokio
::io
::AsyncWrite
> SeqWrite
for TokioWriter
<T
> {
333 self: Pin
<&mut Self>,
336 ) -> Poll
<io
::Result
<usize>> {
337 let this
= unsafe { self.get_unchecked_mut() }
;
338 let got
= ready
!(this
.inner_mut()?
.poll_write(cx
, buf
))?
;
339 this
.position
+= got
as u64;
343 fn poll_position(self: Pin
<&mut Self>, _cx
: &mut Context
) -> Poll
<io
::Result
<u64>> {
344 Poll
::Ready(Ok(self.as_ref().position
))
347 fn poll_flush(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
348 self.inner()?
.poll_flush(cx
)
351 fn poll_close(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
352 let this
= unsafe { self.get_unchecked_mut() }
;
353 match this
.inner
.as_mut() {
354 None
=> return Poll
::Ready(Ok(())),
356 ready
!(unsafe { Pin::new_unchecked(inner).poll_shutdown(cx) }
)?
;
365 pub use tokio_writer
::TokioWriter
;