1use std::fmt;
2use std::io::{self, Read};
3
4#[cfg(feature = "deflate")]
5use flate2::read::ZlibDecoder;
6use rusqlite::blob::Blob;
7
8use super::store::FileBlob;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14#[non_exhaustive]
15pub enum Compression {
16 None,
18
19 #[cfg(feature = "deflate")]
21 Deflate {
22 level: u32,
27 },
28}
29
30impl Compression {
31 #[cfg(feature = "deflate")]
33 pub const FAST: Self = Self::Deflate { level: 1 };
34
35 #[cfg(feature = "deflate")]
37 pub const BEST: Self = Self::Deflate { level: 9 };
38}
39
40enum InnerReader<'conn> {
41 #[cfg(feature = "deflate")]
42 Compressed(ZlibDecoder<Blob<'conn>>),
43 Uncompressed(Blob<'conn>),
44}
45
46impl<'conn> fmt::Debug for InnerReader<'conn> {
47 #[cfg_attr(coverage_nightly, coverage(off))]
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 #[cfg(feature = "deflate")]
51 Self::Compressed(_) => f.debug_tuple("Compressed").finish(),
52 Self::Uncompressed(_) => f.debug_tuple("Uncompressed").finish(),
53 }
54 }
55}
56
57impl<'conn> Read for InnerReader<'conn> {
58 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
59 match self {
60 #[cfg(feature = "deflate")]
61 InnerReader::Compressed(reader) => reader.read(buf),
62 InnerReader::Uncompressed(reader) => reader.read(buf),
63 }
64 }
65}
66
67#[derive(Debug)]
74pub struct FileReader<'conn> {
75 inner: InnerReader<'conn>,
76}
77
78impl<'conn> FileReader<'conn> {
79 pub(super) fn new(blob: FileBlob<'conn>) -> crate::Result<Self> {
80 if blob.is_compressed() {
81 #[cfg(feature = "deflate")]
82 return Ok(Self {
83 inner: InnerReader::Compressed(ZlibDecoder::new(blob.into_blob())),
84 });
85
86 #[cfg(not(feature = "deflate"))]
87 return Err(crate::Error::CompressionNotSupported);
88 }
89
90 Ok(Self {
91 inner: InnerReader::Uncompressed(blob.into_blob()),
92 })
93 }
94}
95
96impl<'conn> Read for FileReader<'conn> {
97 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
98 self.inner.read(buf)
99 }
100}