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}