Skip to main content

molframe_core/io/input/
encoded.rs

1//! Bounded decoding from an existing allocation: O(expanded bytes), no encoded copy.
2
3use super::InputBuffer;
4use super::collect::OutputLimit;
5#[cfg(not(feature = "mmap"))]
6use super::decode::decompress;
7#[cfg(all(feature = "mmap", feature = "gzip"))]
8use super::decode::map_gzip_reader;
9#[cfg(all(feature = "mmap", feature = "zstd"))]
10use super::decode::map_zstd_reader;
11use super::{Compression, Limits};
12use crate::diagnostic::Diagnostic;
13
14impl InputBuffer {
15    /// Adopts plain bytes or decodes a gzip/Zstandard container within `limits`.
16    ///
17    /// Plain bytes retain their allocation. Compressed bytes are decoded directly
18    /// from the supplied vector; expanded output uses private mapped storage when
19    /// `mmap` is enabled. [`Self::from_bytes`] deliberately performs no decoding.
20    ///
21    /// ```
22    /// use molframe_core::io::{InputBuffer, Limits};
23    /// let bytes = b"data_example\n".to_vec();
24    /// let pointer = bytes.as_ptr();
25    /// let input = InputBuffer::from_encoded_bytes(bytes, Limits::default())?;
26    /// assert_eq!(input.as_bytes().as_ptr(), pointer);
27    /// # Ok::<(), molframe_core::diagnostic::Diagnostic>(())
28    /// ```
29    ///
30    /// # Errors
31    ///
32    /// Invalid containers, unavailable decoders, or exceeded byte/expansion limits.
33    pub fn from_encoded_bytes(bytes: Vec<u8>, limits: Limits) -> Result<Self, Diagnostic> {
34        let length = u64::try_from(bytes.len())
35            .map_err(|_| Limits::exceeded("decompressed bytes", bytes.len()))?;
36        OutputLimit::uncompressed(limits).validate(length)?;
37        let compression = Compression::sniff(&bytes);
38        if compression == Compression::None {
39            return Ok(Self::from_bytes(bytes));
40        }
41        #[cfg(not(feature = "mmap"))]
42        {
43            Ok(Self::from_bytes(decompress(bytes, limits)?))
44        }
45        #[cfg(feature = "mmap")]
46        {
47            match compression {
48                #[cfg(feature = "gzip")]
49                Compression::Gzip => {
50                    map_gzip_reader(bytes.as_slice(), length, limits, None).map(Self::from_mapped)
51                }
52                #[cfg(not(feature = "gzip"))]
53                Compression::Gzip => Err(super::decode::unsupported("gzip")),
54                #[cfg(feature = "zstd")]
55                Compression::Zstd => {
56                    map_zstd_reader(bytes.as_slice(), length, limits, None).map(Self::from_mapped)
57                }
58                #[cfg(not(feature = "zstd"))]
59                Compression::Zstd => Err(super::decode::unsupported("zstd")),
60                Compression::None => Ok(Self::from_bytes(bytes)),
61            }
62        }
63    }
64}
65
66#[cfg(test)]
67#[path = "encoded_tests.rs"]
68mod tests;