33 个稳定版本 (3 个主要版本)
使用旧的 Rust 2015
4.0.1 | 2024 年 5 月 27 日 |
---|---|
3.0.0 | 2024 年 4 月 3 日 |
2.5.1 | 2023 年 10 月 28 日 |
2.3.4 | 2023 年 1 月 16 日 |
1.1.0 | 2017 年 6 月 1 日 |
#8 在 嵌入式开发 中
2,893,127 每月下载量
用于 1,715 个 Crates (12 个直接使用)
2MB
31K SLoC
rust-brotli-decompressor
版本 4.0.0 的新功能
- 默认情况下,FFI 已不再激活,以避免在多个依赖 Crates 中包含多个 brotli 版本时出现 ODR 问题。
版本 3.0.0 的新功能
- FFI 被特性门控在 ffi-api 特性标志之后(默认启用)
版本 2.5.0 的新功能
- 如果使用额外的字节调用 write,则它将仅返回消耗的字节
- 后续调用 write 将返回 Ok(0)
版本 2.4.0 的新功能
- 如果读取到文件结束,它将返回 0 字节。
- 后续调用 read 将在文件中有未消耗的字节时出错。
版本 2.3.5 的新功能
- 修复 BrotliFillBitWindow 中的错误
版本 2.3.4 的新功能
- 在解压器读取器/写入器中检查完全消耗的缓冲区。
版本 2.3.x 的新功能
- Write 和 Read 实现的错误处理。
- 修复了在反复调用 Decode 流时某些文件上的小缓冲区大小问题
- 公开 BrotliDecoderIsFinished
版本 2.2.x 的新功能
- 为读取器和写入器类实现into_impl
- 删除了BrotliStateCleanup,因为它在drop()时发生
2.1.2版本的新特性
- 更好地处理暂时性错误(修复了#4)
- 在调试模式下遇到意外的字节时不要恐慌(处理算术溢出)
- 更小的堆栈分配
- 永远不要用nil创建slice::from_raw_parts
- 更好的C FFI恐慌报告
- 将修复brotli问题502和506 b的补丁回滚到旧版本
2.0.0版本的新特性
- 遗留的自定义字典(主要用于测试多线程brotli编码和实验)
- 新机制,请求库只依赖于自定义分配:自--features=std默认开启以来,使用--no-default-features标志。
- 与https://github.com/google/brotli C API完全兼容,成为即插即用的替代品
项目需求
如果构建时传入--no-default-features,则将C brotli解压缩器的直接无stdlib端口移植到Rust
不依赖于Rust stdlib:这个库非常适合在rust内核中解压缩等。
这将有助于在相同的算法、数据结构和优化条件下,进行C和Rust的对比。
预期的当前性能损失来自于
- hgroups中的额外间接引用
- 每次访问时都会检查数组边界
- 无法从[u8]中加载完整的对齐64位或128位项
系统还启用了所有syscalls在分配器的内存池初始生成时“前置加载”。之后,可以激活SECCOMP或其他机制来保护应用程序,如果需要的话
使用零成本rust FFI抽象将rust-brotli-decompressor链接到C代码
此库有符合原始C接口的FFI导出。要构建它们,请进入c目录,并只需在那里键入make。这将构建一个小示例程序和一个cdylib,其中包含适当的ffi以便链接
示例,称为c/main.c,展示了如何使用流接口和非流接口解压缩程序。
如果需要nostdlib版本,则必须使用不稳定的rust(以启用自定义恐慌处理器),然后禁用BrotliDecoderDecompress函数,因为它没有指定自定义malloc的设施
如果选择nostdlib构建,则必须使用自定义malloc,并且必须设置no-stdlib-ffi-binding cargo功能,例如
cargo build --features='no-stdlib no-stdlib-ffi-binding' --release
用法
使用io::Read抽象
let mut input = brotli_decompressor::Decompressor::new(&mut io::stdin(), 4096 /* buffer size */);
然后您可以直接读取输入,就像读取任何其他io::Read类一样
使用Stream Copy抽象
match brotli_decompressor::BrotliDecompress(&mut io::stdin(), &mut io::stdout(), 65536 /* buffer size */) {
Ok(_) => {},
Err(e) => panic!("Error {:?}", e),
}
使用手动内存管理
使用无stdlib的brotli有3个步骤
- 设置内存管理器
- 设置BrotliState
- 在循环中,调用BrotliDecompressStream
详细说明
// at global scope declare a MemPool type -- in this case we'll choose the heap to
// avoid unsafe code, and avoid restrictions of the stack size
declare_stack_allocator_struct!(MemPool, heap);
// at local scope, make a heap allocated buffers to hold uint8's uint32's and huffman codes
let mut u8_buffer = define_allocator_memory_pool!(4096, u8, [0; 32 * 1024 * 1024], heap);
let mut u32_buffer = define_allocator_memory_pool!(4096, u32, [0; 1024 * 1024], heap);
let mut hc_buffer = define_allocator_memory_pool!(4096, HuffmanCode, [0; 4 * 1024 * 1024], heap);
let heap_u8_allocator = HeapPrealloc::<u8>::new_allocator(4096, &mut u8_buffer, bzero);
let heap_u32_allocator = HeapPrealloc::<u32>::new_allocator(4096, &mut u32_buffer, bzero);
let heap_hc_allocator = HeapPrealloc::<HuffmanCode>::new_allocator(4096, &mut hc_buffer, bzero);
// At this point no more syscalls are going to be needed since everything can come from the allocators.
// Feel free to activate SECCOMP jailing or other mechanisms to secure your application if you wish.
// Now it's possible to setup the decompressor state
let mut brotli_state = BrotliState::new(heap_u8_allocator, heap_u32_allocator, heap_hc_allocator);
// at this point the decompressor simply needs an input and output buffer and the ability to track
// the available data left in each buffer
loop {
result = BrotliDecompressStream(&mut available_in, &mut input_offset, &input.slice(),
&mut available_out, &mut output_offset, &mut output.slice_mut(),
&mut written, &mut brotli_state);
// just end the decompression if result is BrotliResult::ResultSuccess or BrotliResult::ResultFailure
}
此接口与C brotli解压缩器使用的接口相同
还可以使用直接调用Box的定制分配器。此示例演示了一种避免在初始分配之后进行后续syscalls的机制