sqlarfs/
stream.rs

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/// The compression method to use when writing to a [`File`].
11///
12/// [`File`]: crate::File
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14#[non_exhaustive]
15pub enum Compression {
16    /// Do not compress writes.
17    None,
18
19    /// Compress writes using the DEFLATE algorithm.
20    #[cfg(feature = "deflate")]
21    Deflate {
22        /// The compression level to use.
23        ///
24        /// This value is on a scale of 0-9, where 0 means "no compression" and 9 means "maximum
25        /// compression."
26        level: u32,
27    },
28}
29
30impl Compression {
31    /// Compression optimized for best speed of encoding.
32    #[cfg(feature = "deflate")]
33    pub const FAST: Self = Self::Deflate { level: 1 };
34
35    /// Compression optimized for minimum output size.
36    #[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/// A readable stream of the data in a [`File`].
68///
69/// This implements [`Read`] for reading a stream of data from a [`File`]. It does not support
70/// seeking.
71///
72/// [`File`]: crate::File
73#[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}