1 //! Asynchronous `pxar` format handling.
6 use std
::task
::{Context, Poll}
;
8 use crate::encoder
::{self, LinkOffset, SeqWrite}
;
12 /// Asynchronous `pxar` encoder.
14 /// This is the `async` version of the `pxar` encoder.
16 pub struct Encoder
<'a
, T
: SeqWrite
+ 'a
> {
17 inner
: encoder
::EncoderImpl
<'a
, T
>,
20 #[cfg(feature = "tokio-io")]
21 impl<'a
, T
: tokio
::io
::AsyncWrite
+ 'a
> Encoder
<'a
, TokioWriter
<T
>> {
22 /// Encode a `pxar` archive into a `tokio::io::AsyncWrite` output.
24 pub async
fn from_tokio(
27 ) -> io
::Result
<Encoder
<'a
, TokioWriter
<T
>>> {
28 Encoder
::new(TokioWriter
::new(output
), metadata
).await
32 #[cfg(feature = "tokio-fs")]
33 impl<'a
> Encoder
<'a
, TokioWriter
<tokio
::fs
::File
>> {
34 /// Convenience shortcut for `File::create` followed by `Encoder::from_tokio`.
35 pub async
fn create
<'b
, P
: AsRef
<Path
>>(
37 metadata
: &'b Metadata
,
38 ) -> io
::Result
<Encoder
<'a
, TokioWriter
<tokio
::fs
::File
>>> {
40 TokioWriter
::new(tokio
::fs
::File
::create(path
.as_ref()).await?
),
47 impl<'a
, T
: SeqWrite
+ 'a
> Encoder
<'a
, T
> {
48 /// Create an asynchronous encoder for an output implementing our internal write interface.
49 pub async
fn new(output
: T
, metadata
: &Metadata
) -> io
::Result
<Encoder
<'a
, T
>> {
51 inner
: encoder
::EncoderImpl
::new(output
, metadata
).await?
,
55 /// Create a new regular file in the archive. This returns a `File` object to which the
56 /// contents have to be written out *completely*. Failing to do so will put the encoder into an
58 pub async
fn create_file
<'b
, P
: AsRef
<Path
>>(
63 ) -> io
::Result
<File
<'b
>>
70 .create_file(metadata
, file_name
.as_ref(), file_size
)
75 // /// Convenience shortcut to add a *regular* file by path including its contents to the archive.
76 // pub async fn add_file<P, F>(
78 // metadata: &Metadata,
81 // content: &mut dyn tokio::io::Read,
82 // ) -> io::Result<()>
87 // self.inner.add_file(
89 // file_name.as_ref(),
91 // content.as_async_reader(),
95 /// Create a new subdirectory. Note that the subdirectory has to be finished by calling the
96 /// `finish()` method, otherwise the entire archive will be in an error state.
97 pub async
fn create_directory
<'b
, P
: AsRef
<Path
>>(
101 ) -> io
::Result
<Encoder
<'b
, &'b
mut dyn SeqWrite
>>
108 .create_directory(file_name
.as_ref(), metadata
)
113 /// Finish this directory. This is mandatory, otherwise the `Drop` handler will `panic!`.
114 pub async
fn finish(self) -> io
::Result
<T
> {
115 self.inner
.finish().await
118 /// Cancel this directory and get back the contained writer.
119 pub fn into_writer(self) -> T
{
120 self.inner
.into_writer()
123 /// Add a symbolic link to the archive.
124 pub async
fn add_symlink
<PF
: AsRef
<Path
>, PT
: AsRef
<Path
>>(
129 ) -> io
::Result
<()> {
131 .add_symlink(metadata
, file_name
.as_ref(), target
.as_ref())
135 /// Add a hard link to the archive.
136 pub async
fn add_hardlink
<PF
: AsRef
<Path
>, PT
: AsRef
<Path
>>(
141 ) -> io
::Result
<()> {
143 .add_hardlink(file_name
.as_ref(), target
.as_ref(), offset
)
147 /// Add a device node to the archive.
148 pub async
fn add_device
<P
: AsRef
<Path
>>(
152 device
: format
::Device
,
153 ) -> io
::Result
<()> {
155 .add_device(metadata
, file_name
.as_ref(), device
)
159 /// Add a device node to the archive.
160 pub async
fn add_fifo
<P
: AsRef
<Path
>>(
164 ) -> io
::Result
<()> {
165 self.inner
.add_fifo(metadata
, file_name
.as_ref()).await
168 /// Add a device node to the archive.
169 pub async
fn add_socket
<P
: AsRef
<Path
>>(
173 ) -> io
::Result
<()> {
174 self.inner
.add_socket(metadata
, file_name
.as_ref()).await
179 pub struct File
<'a
> {
180 inner
: encoder
::FileImpl
<'a
>,
184 /// Get the file offset to be able to reference it with `add_hardlink`.
185 pub fn file_offset(&self) -> LinkOffset
{
186 self.inner
.file_offset()
189 /// Write file data for the current file entry in a pxar archive.
190 pub async
fn write(&mut self, data
: &[u8]) -> io
::Result
<usize> {
191 self.inner
.write(data
).await
194 /// Completely write file data for the current file entry in a pxar archive.
195 pub async
fn write_all(&mut self, data
: &[u8]) -> io
::Result
<()> {
196 self.inner
.write_all(data
).await
200 #[cfg(feature = "tokio-io")]
201 impl<'a
> tokio
::io
::AsyncWrite
for File
<'a
> {
202 fn poll_write(self: Pin
<&mut Self>, cx
: &mut Context
, data
: &[u8]) -> Poll
<io
::Result
<usize>> {
203 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_write(cx
, data
)
206 fn poll_flush(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
207 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_flush(cx
)
210 fn poll_shutdown(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
211 unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
.poll_close(cx
)
215 /// Pxar encoder write adapter for `tokio::io::AsyncWrite`.
216 #[cfg(feature = "tokio-io")]
220 use std
::task
::{Context, Poll}
;
222 use crate::encoder
::SeqWrite
;
224 pub struct TokioWriter
<T
> {
228 impl<T
: tokio
::io
::AsyncWrite
> TokioWriter
<T
> {
229 pub fn new(inner
: T
) -> Self {
230 Self { inner: Some(inner) }
233 fn inner_mut(&mut self) -> io
::Result
<Pin
<&mut T
>> {
237 .ok_or_else(|| io_format_err
!("write after close"))?
;
238 Ok(unsafe { Pin::new_unchecked(inner) }
)
241 fn inner(self: Pin
<&mut Self>) -> io
::Result
<Pin
<&mut T
>> {
242 unsafe { self.get_unchecked_mut() }
.inner_mut()
246 impl<T
: tokio
::io
::AsyncWrite
> SeqWrite
for TokioWriter
<T
> {
248 self: Pin
<&mut Self>,
251 ) -> Poll
<io
::Result
<usize>> {
252 let this
= unsafe { self.get_unchecked_mut() }
;
253 this
.inner_mut()?
.poll_write(cx
, buf
)
256 fn poll_flush(self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
257 self.inner()?
.poll_flush(cx
)
262 #[cfg(feature = "tokio-io")]
263 pub use tokio_writer
::TokioWriter
;
269 use std
::task
::{Context, Poll}
;
276 impl super::SeqWrite
for DummyOutput
{
278 self: Pin
<&mut Self>,
281 ) -> Poll
<io
::Result
<usize>> {
285 fn poll_flush(self: Pin
<&mut Self>, _cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
291 /// Assert that `Encoder` is `Send`
294 let mut encoder
= Encoder
::new(
296 &Metadata
::dir_builder(0o700).build(),
301 .create_directory("baba", &Metadata
::dir_builder(0o700).build())
306 fn test_send
<T
: Send
>(_
: T
) {}