serbzip_core/codecs.rs
1//! Machinery common to all codec implementations.
2
3use crate::transcoder;
4use crate::transcoder::TranscodeError;
5use std::convert::Infallible;
6use std::error::Error;
7use std::io;
8use std::io::BufRead;
9use std::io::Write;
10
11pub mod armenoid;
12pub mod balkanoid;
13
14/// The specification of a codec.
15///
16/// Codecs work line by line. As such, they require two method implementations:
17/// [`compress_line`](Codec::compress_line) — to encode one line of input text, and
18/// [`expand_line`](Codec::expand_line) — to perform the reverse operation.
19///
20/// Compression is not allowed to return an error; the thinking is that all
21/// text should be compressible. Expansion, however, may return an error. It is possible
22/// that the output of compression may have been mangled with, in which case expansion
23/// is not possible.
24pub trait Codec {
25 /// The type of error returned during expansion.
26 type ExpandError: Error;
27
28 /// Compresses a line of text, returning its encoded representation as a [`String`].
29 fn compress_line(&self, line: &str) -> String;
30
31 /// Expands a line of text, returning its decoded representation as a [`String`].
32 ///
33 /// # Errors
34 /// Expansion is not always possible, in which case an [`ExpandError`](Self::ExpandError)
35 /// is returned.
36 fn expand_line(&self, line: &str) -> Result<String, Self::ExpandError>;
37
38 /// A helper method for compressing a series of lines from a given buffered reader,
39 /// outputting the result into the given writer.
40 ///
41 /// # Errors
42 /// [`io::Error`] if the reader or the writer encountered an I/O error.
43 fn compress(&self, r: &mut impl BufRead, w: &mut impl Write) -> Result<(), io::Error> {
44 let result: Result<(), TranscodeError<Infallible>> =
45 transcoder::transcode(r, w, |_, line| Ok(self.compress_line(line)));
46 result.map_err(|err| err.into_io_error().unwrap())
47 }
48
49 /// A helper method for expanding a series of lines from a given buffered reader,
50 /// outputting the result into the given writer.
51 ///
52 /// # Errors
53 /// [`TranscodeError`] if the reader or the writer encountered an I/O error, or
54 /// if the codec was unable to expand a line.
55 fn expand(
56 &self,
57 r: &mut impl BufRead,
58 w: &mut impl Write,
59 ) -> Result<(), TranscodeError<Self::ExpandError>> {
60 transcoder::transcode(r, w, |_, line| self.expand_line(line))
61 }
62}
63
64#[cfg(test)]
65mod tests;