brotlic/lib.rs
1//! # Brotlic
2//!
3//! Brotlic (or BrotliC) is a thin wrapper around [brotli](https://github.com/google/brotli). It
4//! provides Rust bindings to all compression and decompression APIs. On the fly
5//! compression and decompression is supported for both `BufRead` and `Write`
6//! via [`CompressorReader<R>`, `CompressorWriter<W>`, `DecompressorReader<R>`
7//! and `DecompressorWriter<W>`. For low-level instances, see `BrotliEncoder`
8//! and `BrotliDecoder`. These can be configured via `BrotliEncoderOptions` and
9//! `BrotliDecoderOptions` respectively.
10//!
11//! ## High level abstractions
12//!
13//! When dealing with [`BufRead`]:
14//!
15//! * [`DecompressorReader<R>`] - Reads a brotli compressed input stream and
16//! decompresses it.
17//! * [`CompressorReader<R>`] - Reads a stream and compresses it while reading.
18//!
19//! When dealing with [`Write`]:
20//!
21//! * [`CompressorWriter<W>`] - Writes brotli compressed data to the underlying
22//! writer.
23//! * [`DecompressorWriter<W>`] - Writes brotli decompressed data to the
24//! underlying writer.
25//!
26//! To simplify this decision, the following table outlines all the differences:
27//!
28//! | | Input | Output | Wraps |
29//! |---------------------------|--------------|--------------|-------------|
30//! | [`CompressorReader<R>`] | Uncompressed | Compressed | [`BufRead`] |
31//! | [`DecompressorReader<R>`] | Compressed | Uncompressed | [`BufRead`] |
32//! | [`CompressorWriter<W>`] | Uncompressed | Compressed | [`Write`] |
33//! | [`DecompressorWriter<W>`] | Compressed | Uncompressed | [`Write`] |
34//!
35//! [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
36//! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
37//!
38//! To compress a file with brotli:
39//!
40//! ```no_run
41//! use std::fs::File;
42//! use std::io::{self, Write};
43//!
44//! use brotlic::CompressorWriter;
45//!
46//! let mut input = File::open("test.txt")?; // uncompressed text file
47//! let mut output = File::create("test.brotli")?; // compressed text output file
48//! let mut output_compressed = CompressorWriter::new(output);
49//!
50//! output_compressed.write_all(b"test")?;
51//!
52//! # Ok::<(), io::Error>(())
53//! ```
54//!
55//! To decompress that same file:
56//!
57//! ```no_run
58//! use std::fs::File;
59//! use std::io::{self, BufReader, Read};
60//!
61//! use brotlic::DecompressorReader;
62//!
63//! let mut input = BufReader::new(File::open("test.brotli")?); // uncompressed text file
64//! let mut input_decompressed = DecompressorReader::new(input); // requires BufRead
65//!
66//! let mut text = String::new();
67//! input_decompressed.read_to_string(&mut text)?;
68//!
69//! assert_eq!(text, "test");
70//!
71//! # Ok::<(), io::Error>(())
72//! ```
73//!
74//! To compress and decompress in memory:
75//!
76//! ```
77//! use std::io::{self, Read, Write};
78//!
79//! use brotlic::{CompressorWriter, DecompressorReader};
80//!
81//! let input = vec![0; 1024];
82//!
83//! // create a wrapper around Write that supports on the fly brotli compression.
84//! let mut compressor = CompressorWriter::new(Vec::new()); // Vec implements Write
85//! compressor.write_all(input.as_slice());
86//! let compressed_input = compressor.into_inner()?; // read to vec
87//!
88//! // create a wrapper around BufRead that supports on the fly brotli decompression.
89//! let mut decompressor = DecompressorReader::new(compressed_input.as_slice()); // slice is BufRead
90//! let mut decompressed_input = Vec::new();
91//!
92//! decompressor.read_to_end(&mut decompressed_input)?;
93//!
94//! assert_eq!(input, decompressed_input);
95//!
96//! # Ok::<(), io::Error>(())
97//! ```
98//!
99//! ## Customizing compression quality
100//!
101//! Sometimes it can be desirable to trade run-time costs for an even better
102//! compression ratio:
103//!
104//! ```
105//! use brotlic::{BlockSize, BrotliEncoderOptions, CompressorWriter, Quality, WindowSize};
106//!
107//! let encoder = BrotliEncoderOptions::new()
108//! .quality(Quality::best())
109//! .window_size(WindowSize::best())
110//! .block_size(BlockSize::best())
111//! .build()?;
112//!
113//! let compressed_writer = CompressorWriter::with_encoder(encoder, Vec::new());
114//!
115//! # Ok::<(), brotlic::SetParameterError>(())
116//! ```
117//!
118//! It is recommended to not use the encoder directly but instead pass it onto
119//! the higher level abstractions like `CompressorWriter<W>` or
120//! `DecompressorReader<R>`.
121
122#![deny(warnings)]
123#![deny(missing_docs)]
124
125pub mod decode;
126pub mod encode;
127
128use std::error::Error;
129use std::os::raw::c_int;
130use std::{fmt, io};
131
132use brotlic_sys::*;
133pub use decode::{BrotliDecoder, BrotliDecoderOptions, DecompressorReader, DecompressorWriter};
134pub use encode::{BrotliEncoder, BrotliEncoderOptions, CompressorReader, CompressorWriter};
135
136/// Quality level of the brotli compression
137///
138/// [`Quality::best()`] represents the best available quality that maximizes the
139/// compression ratio at the cost of run-time speed. [`Quality::worst()`]
140/// represents the worst available quality that maximizes speed at the expense
141/// of compression ratio.
142#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
143pub struct Quality(u8);
144
145impl Quality {
146 /// Attempts to create a new brotli compression quality.
147 ///
148 /// The range of valid qualities is from 0 to 11 inclusive, where 0 is the
149 /// worst possible quality and 11 is the best possible quality.
150 ///
151 /// # Errors
152 ///
153 /// An [`Err`] will be returned if the `level` is out of the range of valid
154 /// qualities.
155 ///
156 /// # Examples
157 ///
158 /// ```
159 /// use brotlic::Quality;
160 ///
161 /// let worst_quality = Quality::new(0)?;
162 /// let best_quality = Quality::new(11)?;
163 ///
164 /// assert_eq!(worst_quality, Quality::worst());
165 /// assert_eq!(best_quality, Quality::best());
166 /// # Ok::<(), brotlic::SetParameterError>(())
167 /// ```
168 pub const fn new(level: u8) -> Result<Quality, SetParameterError> {
169 match level {
170 BROTLI_MIN_QUALITY..=BROTLI_MAX_QUALITY => Ok(Quality(level)),
171 _ => Err(SetParameterError::InvalidQuality),
172 }
173 }
174
175 /// Creates a new brotli compression quality without checking whether the
176 /// integer represents a valid quality. The range of valid qualities is from
177 /// 0 to 11 inclusive, where 0 is the worst possible quality and 11 is the
178 /// best possible quality. Using any `level` outside of this range will
179 /// result in undefined behaviour.
180 ///
181 /// # Safety
182 ///
183 /// The `level` must be between 0 and 11.
184 ///
185 /// # Examples
186 ///
187 /// ```
188 /// use brotlic::Quality;
189 ///
190 /// // SAFETY: 5 is within the range of valid qualities from 0 to 11
191 /// let quality = unsafe { Quality::new_unchecked(5) };
192 ///
193 /// assert_eq!(quality.level(), 5);
194 /// ```
195 pub const unsafe fn new_unchecked(level: u8) -> Quality {
196 Quality(level)
197 }
198
199 /// The highest quality for brotli compression.
200 ///
201 /// This quality yields maximum compression ratio at the expense of run-time
202 /// speed. It's currently set to 11.
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// use brotlic::Quality;
208 ///
209 /// let best_quality = Quality::new(11)?;
210 ///
211 /// assert_eq!(best_quality, Quality::best());
212 /// # Ok::<(), brotlic::SetParameterError>(())
213 /// ```
214 pub const fn best() -> Quality {
215 Quality(BROTLI_MAX_QUALITY)
216 }
217
218 /// The default quality to use for brotli compression.
219 ///
220 /// This is set to the best possible quality 11.
221 ///
222 /// # Examples
223 ///
224 /// ```
225 /// use brotlic::Quality;
226 ///
227 /// let default_quality = Quality::new(11)?;
228 ///
229 /// assert_eq!(default_quality, Quality::default());
230 /// # Ok::<(), brotlic::SetParameterError>(())
231 /// ```
232 pub const fn default() -> Quality {
233 Quality(BROTLI_DEFAULT_QUALITY)
234 }
235
236 /// The worst quality to use for brotli compression.
237 ///
238 /// This quality yields the worst compression ratio while offering the
239 /// highest run-time speed. It's currently set to 0.
240 ///
241 /// # Examples
242 ///
243 /// ```
244 /// use brotlic::Quality;
245 ///
246 /// let worst_quality = Quality::new(0)?;
247 ///
248 /// assert_eq!(worst_quality, Quality::worst());
249 /// # Ok::<(), brotlic::SetParameterError>(())
250 /// ```
251 pub const fn worst() -> Quality {
252 Quality(BROTLI_MIN_QUALITY)
253 }
254
255 /// Returns an integer representing the quality level.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// use brotlic::Quality;
261 ///
262 /// let quality = Quality::new(4)?;
263 ///
264 /// assert_eq!(quality.level(), 4);
265 /// # Ok::<(), brotlic::SetParameterError>(())
266 /// ```
267 pub const fn level(&self) -> u8 {
268 self.0
269 }
270}
271
272impl Default for Quality {
273 /// Creates a new `Quality` using [`default`].
274 /// See its documentation for more.
275 ///
276 /// [`default`]: Quality::default
277 fn default() -> Self {
278 Quality::default()
279 }
280}
281
282/// The sliding window size (in bits) to use for compression.
283///
284/// Its maximum size is currently limited to 16 MiB, as specified in RFC7932
285/// (Brotli proper). Larger window sizes are supported via [`LargeWindowSize`],
286/// however note that decompression support for these have to be explicitly
287/// enabled. This can be configured via [`large_window_size`] for the matching
288/// [`BrotliDecoder`].
289///
290/// [`large_window_size`]: decode::BrotliDecoderOptions::large_window_size()
291/// [`BrotliDecoder`]: decode::BrotliDecoder
292#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
293pub struct WindowSize(u8);
294
295impl WindowSize {
296 /// Constructs a new sliding window size to use for brotli compression.
297 ///
298 /// Valid `bits` range from 10 (1 KiB) to 24 (16 MiB) inclusive.
299 ///
300 /// # Errors
301 ///
302 /// An [`Err`] will be returned if the `bits` are out of the range of valid
303 /// window sizes.
304 ///
305 /// # Examples
306 ///
307 /// ```
308 /// use brotlic::WindowSize;
309 ///
310 /// let worst_size = WindowSize::new(10)?;
311 /// let best_size = WindowSize::new(24)?;
312 ///
313 /// assert_eq!(worst_size, WindowSize::worst());
314 /// assert_eq!(best_size, WindowSize::best());
315 /// # Ok::<(), brotlic::SetParameterError>(())
316 /// ```
317 pub const fn new(bits: u8) -> Result<WindowSize, SetParameterError> {
318 match bits {
319 BROTLI_MIN_WINDOW_BITS..=BROTLI_MAX_WINDOW_BITS => Ok(WindowSize(bits)),
320 _ => Err(SetParameterError::InvalidWindowSize),
321 }
322 }
323
324 /// Constructs a new sliding window size (in bits) to use for brotli
325 /// compression.
326 ///
327 /// Valid `bits` range from 10 (1 KiB) to 24 (16 MiB) inclusive. Using a
328 /// number of `bits` outside of that range results in undefined
329 /// behaviour.
330 ///
331 /// # Safety
332 ///
333 /// The number of `bits` must be between 10 and 24.
334 ///
335 /// # Examples
336 ///
337 /// ```
338 /// use brotlic::WindowSize;
339 ///
340 /// // SAFETY: 23 is within the valid range of 10 to 24 in window sizes
341 /// let window_size = unsafe { WindowSize::new_unchecked(23) };
342 ///
343 /// assert_eq!(window_size.bits(), 23);
344 /// ```
345 pub const unsafe fn new_unchecked(bits: u8) -> WindowSize {
346 WindowSize(bits)
347 }
348
349 /// Constructs the best sliding window size to use for brotli compression.
350 ///
351 /// This is currently limited to 24 bits (16 MiB) due to RFC7932 (Brotli
352 /// proper). To use larger sliding window sizes, please refer to
353 /// [`LargeWindowSize`]. Note however that explicit support has to be
354 /// enabled by the decoder. This is supported by enabling
355 /// [`large_window_size`] when constructing a [`BrotliDecoder`].
356 ///
357 /// [`large_window_size`]: decode::BrotliDecoderOptions::large_window_size()
358 /// [`BrotliDecoder`]: decode::BrotliDecoder
359 ///
360 /// # Examples
361 ///
362 /// ```
363 /// use brotlic::WindowSize;
364 ///
365 /// let best_size = WindowSize::new(24)?;
366 ///
367 /// assert_eq!(best_size, WindowSize::best());
368 /// # Ok::<(), brotlic::SetParameterError>(())
369 /// ```
370 pub const fn best() -> WindowSize {
371 WindowSize(BROTLI_MAX_WINDOW_BITS)
372 }
373
374 /// Constructs the default sliding window size to use for brotli
375 /// compression.
376 ///
377 /// This is currently set to 22 bits (4 MiB).
378 ///
379 /// # Examples
380 ///
381 /// ```
382 /// use brotlic::WindowSize;
383 ///
384 /// let default_size = WindowSize::new(22)?;
385 ///
386 /// assert_eq!(default_size, WindowSize::default());
387 /// # Ok::<(), brotlic::SetParameterError>(())
388 /// ```
389 pub const fn default() -> WindowSize {
390 WindowSize(BROTLI_DEFAULT_WINDOW)
391 }
392
393 /// Constructs the worst sliding window size to use for brotli compression
394 ///
395 /// This is currently set to 10 bits (1 KiB).
396 ///
397 /// # Examples
398 ///
399 /// ```
400 /// use brotlic::WindowSize;
401 ///
402 /// let worst_size = WindowSize::new(10)?;
403 ///
404 /// assert_eq!(worst_size, WindowSize::worst());
405 /// # Ok::<(), brotlic::SetParameterError>(())
406 /// ```
407 pub const fn worst() -> WindowSize {
408 WindowSize(BROTLI_MIN_WINDOW_BITS)
409 }
410
411 /// Returns an integer representing the window size in bits.
412 ///
413 /// # Examples
414 ///
415 /// ```
416 /// use brotlic::WindowSize;
417 ///
418 /// let window_size = WindowSize::new(24)?;
419 ///
420 /// assert_eq!(window_size.bits(), 24);
421 /// # Ok::<(), brotlic::SetParameterError>(())
422 /// ```
423 pub const fn bits(&self) -> u8 {
424 self.0
425 }
426}
427
428impl Default for WindowSize {
429 /// Creates a new `WindowSize` using [`default`].
430 /// See its documentation for more.
431 ///
432 /// [`default`]: WindowSize::default()
433 fn default() -> Self {
434 WindowSize::default()
435 }
436}
437
438impl TryFrom<LargeWindowSize> for WindowSize {
439 type Error = SetParameterError;
440
441 /// Attempts to construct a [`WindowSize`] from a [`LargeWindowSize`].
442 ///
443 /// This only works if the large window size is currently set to a value
444 /// lower or equal to [`WindowSize::best()`].
445 ///
446 /// # Errors
447 ///
448 /// Large window size does not fit into a window size.
449 fn try_from(large_window_size: LargeWindowSize) -> Result<Self, Self::Error> {
450 WindowSize::new(large_window_size.0)
451 }
452}
453
454/// The large sliding window size (in bits) to use for compression.
455///
456/// Note that using a large sliding window size for a particular compressor
457/// requires explicit support by the decompressor. This is supported by enabling
458/// [`large_window_size`] when constructing a [`BrotliDecoder`].
459///
460/// [`large_window_size`]: decode::BrotliDecoderOptions::large_window_size()
461/// [`BrotliDecoder`]: decode::BrotliDecoder
462#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
463pub struct LargeWindowSize(u8);
464
465impl LargeWindowSize {
466 /// Constructs a new large sliding window size (in bits) to use for brotli
467 /// compression.
468 ///
469 /// Valid `bits` range from 10 (1 KiB) to 30 (1 GiB) inclusive.
470 ///
471 /// # Errors
472 ///
473 /// An [`Err`] will be returned if the `bits` are out of the range of valid
474 /// large window sizes.
475 ///
476 /// # Examples
477 ///
478 /// ```
479 /// use brotlic::LargeWindowSize;
480 ///
481 /// let worst_size = LargeWindowSize::new(10)?;
482 /// let best_size = LargeWindowSize::new(30)?;
483 ///
484 /// assert_eq!(worst_size, LargeWindowSize::worst());
485 /// assert_eq!(best_size, LargeWindowSize::best());
486 /// # Ok::<(), brotlic::SetParameterError>(())
487 /// ```
488 pub const fn new(bits: u8) -> Result<LargeWindowSize, SetParameterError> {
489 match bits {
490 BROTLI_MIN_WINDOW_BITS..=BROTLI_LARGE_MAX_WINDOW_BITS => Ok(LargeWindowSize(bits)),
491 _ => Err(SetParameterError::InvalidWindowSize),
492 }
493 }
494
495 /// Constructs a new large sliding window size (in bits) to use for brotli
496 /// compression.
497 ///
498 /// Valid `bits` range from 10 (1 KiB) to 30 (1 GiB) inclusive. Using a
499 /// number of `bits` outside of that range results in undefined behaviour.
500 ///
501 /// # Safety
502 ///
503 /// The number of `bits` must be between 10 and 30.
504 ///
505 /// # Examples
506 ///
507 /// ```
508 /// use brotlic::LargeWindowSize;
509 ///
510 /// // SAFETY: 28 is within the valid range of 10 to 30 in large window sizes
511 /// let window_size = unsafe { LargeWindowSize::new_unchecked(28) };
512 ///
513 /// assert_eq!(window_size.bits(), 28);
514 /// ```
515 pub const unsafe fn new_unchecked(bits: u8) -> LargeWindowSize {
516 LargeWindowSize(bits)
517 }
518
519 /// Constructs the best large sliding window size to use for brotli
520 /// compression.
521 ///
522 /// This is currently set to 30 bits (1 GiB). Note that this requires
523 /// explicit support by the decompressor. For more information see
524 /// [`LargeWindowSize`].
525 ///
526 /// # Examples
527 ///
528 /// ```
529 /// use brotlic::LargeWindowSize;
530 ///
531 /// let best_size = LargeWindowSize::new(30)?;
532 ///
533 /// assert_eq!(best_size, LargeWindowSize::best());
534 /// # Ok::<(), brotlic::SetParameterError>(())
535 /// ```
536 pub const fn best() -> LargeWindowSize {
537 LargeWindowSize(BROTLI_LARGE_MAX_WINDOW_BITS)
538 }
539
540 /// Constructs the default large sliding window size to use for brotli
541 /// compression.
542 ///
543 /// This is currently set to 22 bits (4 MiB).
544 ///
545 /// # Examples
546 ///
547 /// ```
548 /// use brotlic::LargeWindowSize;
549 ///
550 /// let default_size = LargeWindowSize::new(22)?;
551 ///
552 /// assert_eq!(default_size, LargeWindowSize::default());
553 /// # Ok::<(), brotlic::SetParameterError>(())
554 /// ```
555 pub const fn default() -> LargeWindowSize {
556 LargeWindowSize(BROTLI_DEFAULT_WINDOW)
557 }
558
559 /// Constructs the worst large sliding window size to use for brotli
560 /// compression
561 ///
562 /// This is currently set to 10 bits (1 KiB).
563 ///
564 /// # Examples
565 ///
566 /// ```
567 /// use brotlic::LargeWindowSize;
568 ///
569 /// let worst_size = LargeWindowSize::new(10)?;
570 ///
571 /// assert_eq!(worst_size, LargeWindowSize::worst());
572 /// # Ok::<(), brotlic::SetParameterError>(())
573 /// ```
574 pub const fn worst() -> LargeWindowSize {
575 LargeWindowSize(BROTLI_MIN_WINDOW_BITS)
576 }
577
578 /// Returns an integer representing the large window size in bits.
579 ///
580 /// # Examples
581 ///
582 /// ```
583 /// use brotlic::LargeWindowSize;
584 ///
585 /// let window_size = LargeWindowSize::new(28)?;
586 ///
587 /// assert_eq!(window_size.bits(), 28);
588 /// # Ok::<(), brotlic::SetParameterError>(())
589 /// ```
590 pub const fn bits(&self) -> u8 {
591 self.0
592 }
593}
594
595impl Default for LargeWindowSize {
596 /// Creates a new `LargeWindowSize` using [`default`].
597 /// See its documentation for more.
598 ///
599 /// [`default`]: LargeWindowSize::default()
600 fn default() -> Self {
601 LargeWindowSize::default()
602 }
603}
604
605impl From<WindowSize> for LargeWindowSize {
606 /// Constructs a [`LargeWindowSize`] from a [`WindowSize`].
607 ///
608 /// This always works because a `LargeWindowSize` covers a larger range than
609 /// the regular `WindowSize`. The inverse is not true, however.
610 fn from(window_size: WindowSize) -> Self {
611 LargeWindowSize(window_size.0)
612 }
613}
614
615/// The recommended input block size (in bits) to use for compression.
616///
617/// The compressor may reduce this value at its leisure, for example when the
618/// input size is small. Larger block sizes allow better compression at the
619/// expense of using more memory. Rough formula for memory required is `3 <<
620/// bits` bytes.
621#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
622pub struct BlockSize(u8);
623
624impl BlockSize {
625 /// Constructs a new block size (in bits) to use for brotli compression.
626 ///
627 /// Valid `bits` range from 16 to 24 inclusive.
628 ///
629 /// # Errors
630 ///
631 /// An [`Err`] will be returned if the `bits` are out of the range of valid
632 /// block sizes.
633 ///
634 /// # Examples
635 ///
636 /// ```
637 /// use brotlic::BlockSize;
638 ///
639 /// let worst_size = BlockSize::new(16)?;
640 /// let best_size = BlockSize::new(24)?;
641 ///
642 /// assert_eq!(worst_size, BlockSize::worst());
643 /// assert_eq!(best_size, BlockSize::best());
644 /// # Ok::<(), brotlic::SetParameterError>(())
645 /// ```
646 pub const fn new(bits: u8) -> Result<BlockSize, SetParameterError> {
647 match bits {
648 BROTLI_MIN_INPUT_BLOCK_BITS..=BROTLI_MAX_INPUT_BLOCK_BITS => Ok(BlockSize(bits)),
649 _ => Err(SetParameterError::InvalidBlockSize),
650 }
651 }
652
653 /// Constructs a new block size (in bits) to use for brotli compression.
654 ///
655 /// Valid `bits` range from 16 to 24 inclusive. Using any number of bits
656 /// outside of that range results in undefined behaviour.
657 ///
658 /// # Safety
659 ///
660 /// The number of `bits` must be between 16 and 24.
661 ///
662 /// # Examples
663 ///
664 /// ```
665 /// use brotlic::BlockSize;
666 ///
667 /// let block_size = unsafe { BlockSize::new_unchecked(22) };
668 ///
669 /// assert_eq!(block_size.bits(), 22);
670 /// ```
671 pub const fn new_unchecked(bits: u8) -> BlockSize {
672 BlockSize(bits)
673 }
674
675 /// Constructs the best block size (in bits) to use for brotli compression.
676 ///
677 /// This will allow better compression at the expense of memory usage.
678 /// Currently it is set to 24 bits.
679 ///
680 /// # Examples
681 ///
682 /// ```
683 /// use brotlic::BlockSize;
684 ///
685 /// let best_size = BlockSize::new(24)?;
686 ///
687 /// assert_eq!(best_size, BlockSize::best());
688 /// # Ok::<(), brotlic::SetParameterError>(())
689 /// ```
690 pub const fn best() -> BlockSize {
691 BlockSize(BROTLI_MAX_INPUT_BLOCK_BITS)
692 }
693
694 /// Constructs the worst block size (in bits) to use for brotli compression.
695 ///
696 /// This will consume the least amount of memory at the expense of
697 /// compression ratio. Currently it is set to 16 bits.
698 ///
699 /// # Examples
700 ///
701 /// ```
702 /// use brotlic::BlockSize;
703 ///
704 /// let worst_size = BlockSize::new(16)?;
705 ///
706 /// assert_eq!(worst_size, BlockSize::worst());
707 /// # Ok::<(), brotlic::SetParameterError>(())
708 /// ```
709 pub const fn worst() -> BlockSize {
710 BlockSize(BROTLI_MIN_INPUT_BLOCK_BITS)
711 }
712
713 /// Returns an integer representing the block size in bits.
714 ///
715 /// # Examples
716 ///
717 /// ```
718 /// use brotlic::BlockSize;
719 ///
720 /// let block_size = BlockSize::new(23)?;
721 ///
722 /// assert_eq!(block_size.bits(), 23);
723 /// # Ok::<(), brotlic::SetParameterError>(())
724 /// ```
725 pub const fn bits(&self) -> u8 {
726 self.0
727 }
728}
729
730/// Allows to tune a brotli compressor for a specific type of input.
731#[derive(Debug, Copy, Clone, Eq, PartialEq)]
732pub enum CompressionMode {
733 /// No known attributes about the input data.
734 Generic = BrotliEncoderMode_BROTLI_MODE_GENERIC as isize,
735
736 /// Tune compression for UTF-8 formatted text input.
737 Text = BrotliEncoderMode_BROTLI_MODE_TEXT as isize,
738
739 /// Tune compression for WOFF 2.0 fonts
740 Font = BrotliEncoderMode_BROTLI_MODE_FONT as isize,
741}
742
743impl Default for CompressionMode {
744 /// Creates a `CompressionMode` using [`Generic`].
745 /// See its documentation for more.
746 ///
747 /// [`Generic`]: CompressionMode::Generic
748 fn default() -> Self {
749 CompressionMode::Generic
750 }
751}
752
753/// An error returned by [`compress`].
754#[derive(Debug, Copy, Clone, Eq, PartialEq)]
755pub struct CompressError;
756
757impl fmt::Display for CompressError {
758 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
759 f.write_str("buffer was too small or compression error occurred")
760 }
761}
762
763impl Error for CompressError {}
764
765impl From<CompressError> for io::Error {
766 fn from(err: CompressError) -> Self {
767 io::Error::new(io::ErrorKind::Other, err)
768 }
769}
770
771/// An error returned by [`decompress`].
772#[derive(Debug, Copy, Clone, Eq, PartialEq)]
773pub struct DecompressError;
774
775impl fmt::Display for DecompressError {
776 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
777 f.write_str("buffer was too small or decompression error occurred")
778 }
779}
780
781impl Error for DecompressError {}
782
783impl From<DecompressError> for io::Error {
784 fn from(err: DecompressError) -> Self {
785 io::Error::new(io::ErrorKind::Other, err)
786 }
787}
788
789/// An error returned by [`BrotliEncoderOptions::build`] and
790/// [`BrotliDecoderOptions::build`]
791///
792/// [`BrotliEncoderOptions::build`]: encode::BrotliEncoderOptions::build
793/// [`BrotliDecoderOptions::build`]: decode::BrotliDecoderOptions::build
794#[derive(Debug, Copy, Clone, Eq, PartialEq)]
795#[non_exhaustive]
796pub enum SetParameterError {
797 /// The encoder or decoder returned an error.
798 ///
799 /// This error originates from `BrotliEncoderSetParameter` or
800 /// `BrotliDecoderSetParameter` being unsuccessful.
801 Generic,
802
803 /// Postfix bits were out of range.
804 InvalidPostfix,
805
806 /// Direct distance codes were out of range or were given in invalid
807 /// increments.
808 InvalidDirectDistanceCodes,
809
810 /// The stream offset was beyond its maximum offset.
811 InvalidStreamOffset,
812
813 /// The quality was out of range.
814 InvalidQuality,
815
816 /// sliding window size bits were out of range.
817 InvalidWindowSize,
818
819 /// Block size bits were out of range.
820 InvalidBlockSize,
821}
822
823impl fmt::Display for SetParameterError {
824 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
825 match self {
826 SetParameterError::Generic => f.write_str("invalid parameter"),
827 SetParameterError::InvalidPostfix => f.write_str("invalid number of postfix bits"),
828 SetParameterError::InvalidDirectDistanceCodes => {
829 f.write_str("invalid number of direct distance codes")
830 }
831 SetParameterError::InvalidStreamOffset => f.write_str("stream offset was out of range"),
832 SetParameterError::InvalidQuality => f.write_str("quality out of range"),
833 SetParameterError::InvalidWindowSize => f.write_str("window size out of range"),
834 SetParameterError::InvalidBlockSize => f.write_str("block size out of range"),
835 }
836 }
837}
838
839impl Error for SetParameterError {}
840
841/// Read all bytes from `input` and compress them into `output`, returning how
842/// many bytes were written.
843///
844/// The compression will use the specified `quality` (see [`Quality`] for more
845/// information), `window_size` (see [`WindowSize`] for more information) and
846/// `mode` (see [`CompressionMode`] for more information). The compressed
847/// `input` using the specified compression settings must fit into `output`,
848/// otherwise an error is returned and the compression will be aborted. To get
849/// an upper bound when `quality` is 2 or higher, use [`compress_bound`].
850///
851/// # Errors
852///
853/// An [`Err`] will be returned if:
854///
855/// * `output` is not large enough to contain the compressed data
856/// * A generic compression error occurs
857/// * memory allocation failed
858///
859/// # Examples
860///
861/// ```
862/// use brotlic::{compress, CompressionMode, Quality, WindowSize};
863///
864/// let input = vec![0; 1024];
865/// let mut output = vec![0; 1024];
866///
867/// let bytes_written = compress(
868/// input.as_slice(),
869/// output.as_mut_slice(),
870/// Quality::default(),
871/// WindowSize::default(),
872/// CompressionMode::Generic,
873/// )?;
874///
875/// assert!(bytes_written < input.len());
876/// # Ok::<(), brotlic::CompressError>(())
877/// ```
878#[doc(alias = "BrotliEncoderCompress")]
879pub fn compress(
880 input: &[u8],
881 output: &mut [u8],
882 quality: Quality,
883 window_size: WindowSize,
884 mode: CompressionMode,
885) -> Result<usize, CompressError> {
886 let mut output_size = output.len();
887
888 let res = unsafe {
889 BrotliEncoderCompress(
890 quality.0 as c_int,
891 window_size.0 as c_int,
892 mode as BrotliEncoderMode,
893 input.len(),
894 input.as_ptr(),
895 &mut output_size as *mut usize,
896 output.as_mut_ptr(),
897 )
898 };
899
900 if res != 0 {
901 Ok(output_size)
902 } else {
903 Err(CompressError)
904 }
905}
906
907/// Returns an upper bound for compression.
908///
909/// Given an input of `input_size` bytes in size and a `quality`, determine an
910/// upper bound for compression. This may be larger than `input_size`. The
911/// result is only valid for a quality of at least `2`, as per documentation of
912/// `BrotliEncoderMaxCompressedSize`. For qualities lower than `2`, `None` will
913/// be returned.
914#[doc(alias = "BrotliEncoderMaxCompressedSize")]
915pub fn compress_bound(input_size: usize, quality: Quality) -> Option<usize> {
916 if quality.0 >= 2 {
917 Some(unsafe { BrotliEncoderMaxCompressedSize(input_size) })
918 } else {
919 None
920 }
921}
922
923/// Returns peak memory usage for a given quality and window size
924///
925/// Given an input of `input_size` bytes in size, a `quality` and a
926/// `window_size`, estimate the peak memory usage in bytes, not counting the
927/// memory needed for the input and output.
928#[doc(alias = "BrotliEncoderEstimatePeakMemoryUsage")]
929pub fn compress_estimate_max_mem_usage(
930 input_size: usize,
931 quality: Quality,
932 window_size: impl Into<LargeWindowSize>,
933) -> usize {
934 unsafe {
935 BrotliEncoderEstimatePeakMemoryUsage(quality.0 as _, window_size.into().0 as _, input_size)
936 }
937}
938
939/// Read all bytes from `input` and decompress them into `output`, returning how
940/// many bytes were written.
941///
942/// The uncompressed `input` must fit into `output`, otherwise an error is
943/// returned and the decompression will be aborted.
944///
945/// # Errors
946///
947/// An [`Err`] will be returned if:
948///
949/// * `input` is corrupted
950/// * memory allocation failed
951/// * `output` is not large enough to hold uncompressed `input`
952///
953/// # Examples
954///
955/// ```
956/// use brotlic::{compress, decompress, CompressionMode, Quality, WindowSize};
957///
958/// let input = vec![0; 1024];
959/// let mut encoded = vec![1; 1024];
960/// let mut decoded = vec![2; 1024];
961///
962/// let bytes_written = compress(
963/// input.as_slice(),
964/// encoded.as_mut_slice(),
965/// Quality::default(),
966/// WindowSize::default(),
967/// CompressionMode::Generic,
968/// )?;
969///
970/// let encoded = &encoded[..bytes_written];
971/// let bytes_written = decompress(encoded, decoded.as_mut_slice())?;
972/// let decoded = &decoded[..bytes_written];
973///
974/// assert_eq!(input, decoded);
975/// # Ok::<(), std::io::Error>(())
976/// ```
977#[doc(alias = "BrotliDecoderDecompress")]
978pub fn decompress(input: &[u8], output: &mut [u8]) -> Result<usize, DecompressError> {
979 let mut output_size = output.len();
980
981 let res = unsafe {
982 BrotliDecoderDecompress(
983 input.len(),
984 input.as_ptr(),
985 &mut output_size as *mut usize,
986 output.as_mut_ptr(),
987 )
988 };
989
990 if res == BrotliDecoderResult_BROTLI_DECODER_RESULT_SUCCESS {
991 Ok(output_size)
992 } else {
993 Err(DecompressError)
994 }
995}
996
997/// An error returned by `into_inner`.
998///
999/// This error combines an error that happened while processing data, and the
1000/// instance object which may be used to recover from the condition.
1001#[derive(Debug)]
1002pub struct IntoInnerError<I>(I, io::Error);
1003
1004impl<I> IntoInnerError<I> {
1005 fn new(inner: I, error: io::Error) -> Self {
1006 Self(inner, error)
1007 }
1008
1009 /// Returns the error which caused the call to `into_inner()` to fail.
1010 pub fn error(&self) -> &io::Error {
1011 &self.1
1012 }
1013
1014 /// Returns the instance which generated the error
1015 pub fn into_inner(self) -> I {
1016 self.0
1017 }
1018
1019 /// Returns the error which caused the `into_inner` call to fail. This is
1020 /// used to obtain ownership of the error in contrast to `error`.
1021 pub fn into_error(self) -> io::Error {
1022 self.1
1023 }
1024
1025 /// Returns both the error and the instance that generated it. This is used
1026 /// to obtain ownership of both of them.
1027 pub fn into_parts(self) -> (io::Error, I) {
1028 (self.1, self.0)
1029 }
1030}
1031
1032impl<I> From<IntoInnerError<I>> for io::Error {
1033 fn from(iie: IntoInnerError<I>) -> io::Error {
1034 iie.1
1035 }
1036}
1037
1038impl<I: fmt::Debug + Send> Error for IntoInnerError<I> {}
1039
1040impl<I> fmt::Display for IntoInnerError<I> {
1041 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1042 self.error().fmt(f)
1043 }
1044}