]> git.proxmox.com Git - pxar.git/blob - src/decoder/sync.rs
drop custom poll_fn, require rust 1.64
[pxar.git] / src / decoder / sync.rs
1 //! Blocking `pxar` format handling.
2
3 use std::io;
4 use std::path::Path;
5 use std::pin::Pin;
6 use std::task::{Context, Poll};
7
8 use crate::decoder::{self, SeqRead};
9 use crate::util::poll_result_once;
10 use crate::Entry;
11
12 /// Blocking `pxar` decoder.
13 ///
14 /// This is the blocking I/O version of the `pxar` decoder. This will *not* work with an
15 /// asynchronous I/O object. I/O must always return `Poll::Ready`.
16 ///
17 /// Attempting to use a `Waker` from this context *will* `panic!`
18 ///
19 /// If you need to use asynchronous I/O, use `aio::Decoder`.
20 #[repr(transparent)]
21 pub struct Decoder<T> {
22 inner: decoder::DecoderImpl<T>,
23 }
24
25 impl<T: io::Read> Decoder<StandardReader<T>> {
26 /// Decode a `pxar` archive from a regular `std::io::Read` input.
27 #[inline]
28 pub fn from_std(input: T) -> io::Result<Self> {
29 Decoder::new(StandardReader::new(input))
30 }
31
32 /// Get a direct reference to the reader contained inside the contained [`StandardReader`].
33 pub fn input(&mut self) -> &T {
34 self.inner.input().inner()
35 }
36 }
37
38 impl Decoder<StandardReader<std::fs::File>> {
39 /// Convenience shortcut for `File::open` followed by `Accessor::from_file`.
40 pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
41 Self::from_std(std::fs::File::open(path.as_ref())?)
42 }
43 }
44
45 impl<T: SeqRead> Decoder<T> {
46 /// Create a *blocking* decoder from an input implementing our internal read interface.
47 ///
48 /// Note that the `input`'s `SeqRead` implementation must always return `Poll::Ready` and is
49 /// not allowed to use the `Waker`, as this will cause a `panic!`.
50 pub fn new(input: T) -> io::Result<Self> {
51 Ok(Self {
52 inner: poll_result_once(decoder::DecoderImpl::new(input))?,
53 })
54 }
55
56 /// Internal helper for `Accessor`. In this case we have the low-level state machine, and the
57 /// layer "above" the `Accessor` propagates the actual type (sync vs async).
58 pub(crate) fn from_impl(inner: decoder::DecoderImpl<T>) -> Self {
59 Self { inner }
60 }
61
62 // I would normally agree with clippy, but this here is to be consistent with the async
63 // counterpart, and we *do* implement Iterator as well, so that's fine!
64 #[allow(clippy::should_implement_trait)]
65 /// If this is a directory entry, get the next item inside the directory.
66 pub fn next(&mut self) -> Option<io::Result<Entry>> {
67 poll_result_once(self.inner.next_do()).transpose()
68 }
69
70 /// Get a reader for the contents of the current entry, if the entry has contents.
71 pub fn contents(&mut self) -> Option<Contents<T>> {
72 self.inner.content_reader().map(|inner| Contents { inner })
73 }
74
75 /// Get the size of the current contents, if the entry has contents.
76 pub fn content_size(&self) -> Option<u64> {
77 self.inner.content_size()
78 }
79
80 /// Include goodbye tables in iteration.
81 pub fn enable_goodbye_entries(&mut self, on: bool) {
82 self.inner.with_goodbye_tables = on;
83 }
84 }
85
86 impl<T: SeqRead> Iterator for Decoder<T> {
87 type Item = io::Result<Entry>;
88
89 fn next(&mut self) -> Option<Self::Item> {
90 Decoder::next(self)
91 }
92 }
93
94 /// Pxar decoder read adapter for `std::io::Read`.
95 pub struct StandardReader<T> {
96 inner: T,
97 }
98
99 impl<T: io::Read> StandardReader<T> {
100 /// Make a new [`StandardReader`].
101 pub fn new(inner: T) -> Self {
102 Self { inner }
103 }
104
105 /// Get an immutable reference to the contained reader.
106 pub fn inner(&self) -> &T {
107 &self.inner
108 }
109 }
110
111 impl<T: io::Read> SeqRead for StandardReader<T> {
112 fn poll_seq_read(
113 self: Pin<&mut Self>,
114 _cx: &mut Context,
115 buf: &mut [u8],
116 ) -> Poll<io::Result<usize>> {
117 Poll::Ready(unsafe { self.get_unchecked_mut() }.inner.read(buf))
118 }
119 }
120
121 /// Reader for file contents inside a pxar archive.
122 pub struct Contents<'a, T: SeqRead> {
123 inner: decoder::Contents<'a, T>,
124 }
125
126 impl<'a, T: SeqRead> io::Read for Contents<'a, T> {
127 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
128 poll_result_once(super::seq_read(&mut self.inner, buf))
129 }
130 }