#streaming #iterator #data-streaming #fallible #vec-u8 #buffer #items

streaming-decompression

适用于解压缩的故障安全流迭代器

3 个版本

0.1.2 2022年7月30日
0.1.1 2022年7月30日
0.1.0 2021年10月15日

#128 in 压缩

Download history 17309/week @ 2024-04-20 17026/week @ 2024-04-27 21196/week @ 2024-05-04 22905/week @ 2024-05-11 22181/week @ 2024-05-18 21928/week @ 2024-05-25 21377/week @ 2024-06-01 20778/week @ 2024-06-08 20179/week @ 2024-06-15 23536/week @ 2024-06-22 22722/week @ 2024-06-29 22485/week @ 2024-07-06 19996/week @ 2024-07-13 20764/week @ 2024-07-20 23920/week @ 2024-07-27 24851/week @ 2024-08-03

93,557 每月下载量
166 个crate中(直接使用2个) 使用

Apache-2.0

11KB
159

此crate包含一个针对解压缩优化的 FallibleStreamingIterator

使用压缩格式的库通常会面临的一个典型问题是需要保留一个中间缓冲区以解压缩多个项目。具体来说,使用

fn decompress(compressed: Vec<u8>) -> Vec<u8> {
    unimplemented!("Decompress")
}

的实现效率低下,因为它们需要为每次解压缩分配一个新的 Vec<u8>,并且这种分配随着项目平均 解压缩 大小而扩展。

解决此问题的典型方法是为

fn decompress(compressed: Vec<u8>, decompressed: &mut Vec<u8>) {
    decompressed.clear();
    unimplemented!("Decompress into `decompressed`, maybe re-allocing it.")
}

此类API避免了每个项目分配一次,但要求用户在迭代之间处理保留 解压缩。这种模式当前无法使用 Iterator API 实现。

此crate提供了 Decompressor,这是一个 FallibleStreamingIterator,它消耗一个压缩项目的 Iterator 并生成解压缩项目,同时维护一个内部 Vec<u8>,该缓冲区会在项目之间自动重用。

示例

use streaming_codec::{Decompressor, Compressed, Decompressed, FallibleStreamingIterator};

// An item that is decompressable
#[derive(Debug, PartialEq)]
struct CompressedItem {
    pub metadata: String,
    pub data: Vec<u8>,
}
impl Compressed for CompressedItem {
    fn is_compressed(&self) -> bool {
        // whether it is decompressed or not depends on some metadata.
        self.metadata == "is_compressed"
    }
}

// A decompressed item
#[derive(Debug, PartialEq)]
struct DecompressedItem {
    pub metadata: String,
    pub data: Vec<u8>,
}

impl Decompressed for DecompressedItem {
    fn buffer_mut(&mut self) -> &mut Vec<u8> {
        &mut self.data
    }
}

// the decompression function. This could call LZ4, Snappy, etc.
fn decompress(
    mut i: CompressedItem,
    buffer: &mut Vec<u8>,
) -> Result<DecompressedItem, std::convert::Infallible> {
    if i.is_compressed() {
        // the actual decompression, here identity, but more complex stuff can happen.
        buffer.clear();
        buffer.extend(&mut i.data.iter().rev());
    } else {
        std::mem::swap(&mut i.data, buffer);
    };
    Ok(DecompressedItem {
        metadata: i.metadata,
        data: std::mem::take(buffer),
    })
}

fn main() -> Result<(), std::convert::Infallible> {
   // consider some compressed items
   let item1 = CompressedItem {
       metadata: "is_compressed".to_string(),
       data: vec![1, 2, 3],
   };
   let item2 = CompressedItem {
       metadata: "is_compressed".to_string(),
       data: vec![4, 5, 6],
   };
   let iter = vec![Ok(item1), Ok(item2)].into_iter();

   let buffer = vec![0; 4];  // the internal buffer: it could contain anything.
   let mut decompressor = Decompressor::new(iter, buffer, decompress);

   let item = decompressor.next()?.unwrap();
   // the item was decompressed
   assert_eq!(item.data, vec![3, 2, 1]);
   assert_eq!(item.metadata, "is_compressed".to_string());

   let item = decompressor.next()?.unwrap();
   // the item was decompressed
   assert_eq!(item.data, vec![6, 5, 4]);
   assert_eq!(item.metadata, "is_compressed".to_string());

   assert_eq!(decompressor.next()?, None);

   // we can re-use the internal buffer if we wish to
   let internal = decompressor.into_inner();
   assert_eq!(internal, vec![6, 5, 4]);
   Ok(())
}

许可证

许可方式为以下之一

由您自行选择。

贡献

除非您明确表示,否则您有意提交的任何贡献,根据Apache-2.0许可证的定义,应以上述双许可证方式授权,不附加任何额外条款或条件。

依赖项

~23KB