I used Brotly-sys but it seems unmaintened. So I use Brotli. I do an interface to compress and decompress (I use lzma and zstd too):
use std::io::{self, Write};
pub use brotli::writer::DecompressorWriter;
pub use brotli::enc::writer::CompressorWriter;
use super::Coder;
impl<W: Write> Coder<W> for DecompressorWriter<W> {
fn get_mut(&mut self) -> &mut W {
DecompressorWriter::get_mut(self)
}
fn finish(self) -> std::io::Result<W> {
DecompressorWriter::flush(&mut self).map_err(|_| {
io::Error::new(io::ErrorKind::Other, "brotli decoder failed to finalize stream")
});
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
impl<W: Write> Coder<W> for CompressorWriter<W> {
fn get_mut(&mut self) -> &mut W {
CompressorWriter::get_mut(self)
}
fn finish(self) -> std::io::Result<W> {
self.flush()?;
CompressorWriter::flush(&mut self).map_err(|_| {
io::Error::new(io::ErrorKind::Other, "brotli encoder failed to finalize stream")
})
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
But get
error[E0308]: mismatched types
--> lib/src/codecs/brotli.rs:13:24
|
13 | fn finish(self) -> std::io::Result<W> {
| ------ ^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
|
= note: expected enum `std::result::Result<W, std::io::Error>`
found unit type `()`
error[E0308]: mismatched types
--> lib/src/codecs/brotli.rs:31:9
|
24 | impl<W: Write> Coder<W> for CompressorWriter<W> {
| - this type parameter
...
29 | fn finish(self) -> std::io::Result<W> {
| ------------------ expected `std::result::Result<W, std::io::Error>` because of return type
30 | self.flush()?;
31 | / CompressorWriter::flush(&mut self).map_err(|_| {
32 | | io::Error::new(io::ErrorKind::Other, "brotli encoder failed to finalize stream")
33 | | })
| |__________^ expected type parameter `W`, found `()`
|
= note: expected enum `std::result::Result<W, _>`
found enum `std::result::Result<(), _>`
But flush
function doesn't implement Write
trait.
Coder
interface is here: https://github.com/Ludea/speedupdate-rs/blob/master/lib/src/codecs/mod.rs#L21
So how can I fix my issue ? (I can provide GH repo with this issue) I get this issue on MacOS / Win64 / Linux x86_64. Thanks
Your Coder
trait is not compatible with the CompressorWriter
struct. You might have to modify the Coder
trait.
I assume the flow of Coder
is:
Coder
.Write
object by calling get_mut()
.finish()
and retrieve the compressed data from its return value.Your trait forces the return value of get_mut()
to be identical to the return value of finish()
, which isn't the case for CompressorWriter
.
You don't need to introduce a new generic for this, though; you can simply return &mut dyn Write
from your get_mut()
function. This might require some minor tweaks with your other implementations of Coder
, but should work.
Minor side note: I renamed get_mut()
to get_input_writer()
, because it was clashing with CompressorWriter::get_mut()
, making dealing with it much more annoying.
use std::io::{self, Write};
pub use brotli::enc::writer::CompressorWriter;
pub use brotli::writer::DecompressorWriter;
trait Coder<W> {
fn get_input_writer(&mut self) -> &mut dyn Write;
fn finish(self) -> io::Result<W>;
fn finish_boxed(self: Box<Self>) -> io::Result<W>;
}
impl<W: Write> Coder<W> for CompressorWriter<W> {
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
self.flush().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli encoder failed to finalize stream",
)
})?;
Ok(self.into_inner())
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
impl<W: Write> Coder<W> for DecompressorWriter<W> {
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
self.flush().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli decoder failed to finalize stream",
)
})?;
self.into_inner().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli decoder failed to finalize stream",
)
})
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
fn main() {
// Encode
let mut coder: Box<dyn Coder<_>> = Box::new(CompressorWriter::with_params(
Vec::new(),
1024,
&Default::default(),
));
coder.get_input_writer().write_all(b"Hello world!").unwrap();
let output = coder.finish_boxed().unwrap();
println!("{:?}", output);
// Decode
let mut decoder: Box<dyn Coder<_>> = Box::new(DecompressorWriter::new(Vec::new(), 1024));
decoder.get_input_writer().write_all(&output).unwrap();
let output = decoder.finish_boxed().unwrap();
println!("{:?}", String::from_utf8_lossy(&output));
}
[139, 5, 128, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 3]
"Hello world!"
While you are on it, I'd also change some other things, for convenience:
into_boxed_coder
function for convenience.use std::io::{self, Write};
pub use brotli::enc::writer::CompressorWriter;
pub use brotli::writer::DecompressorWriter;
trait Coder {
type Out;
fn into_boxed_coder(self) -> Box<dyn Coder<Out = Self::Out>>
where
Self: Sized + 'static,
{
Box::new(self)
}
fn get_input_writer(&mut self) -> &mut dyn Write;
fn finish(self) -> io::Result<Self::Out>;
fn finish_boxed(self: Box<Self>) -> io::Result<Self::Out>;
}
impl<W: Write> Coder for CompressorWriter<W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
self.flush().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli encoder failed to finalize stream",
)
})?;
Ok(self.into_inner())
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
impl<W: Write> Coder for DecompressorWriter<W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
self.flush().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli decoder failed to finalize stream",
)
})?;
self.into_inner().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli decoder failed to finalize stream",
)
})
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
fn main() {
// Encode
let mut coder =
CompressorWriter::with_params(Vec::new(), 1024, &Default::default()).into_boxed_coder();
coder.get_input_writer().write_all(b"Hello world!").unwrap();
let output = coder.finish_boxed().unwrap();
println!("{:?}", output);
// Decode
let mut decoder = DecompressorWriter::new(Vec::new(), 1024).into_boxed_coder();
decoder.get_input_writer().write_all(&output).unwrap();
let output = decoder.finish_boxed().unwrap();
println!("{:?}", String::from_utf8_lossy(&output));
}
[139, 5, 128, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 3]
"Hello world!"
Here is a more complete example with implementations for brotli
, zstd
and lzma
:
use std::{
io::{self, Write},
ops::Deref,
};
trait Coder {
type Out;
fn into_boxed_coder(self) -> Box<dyn Coder<Out = Self::Out>>
where
Self: Sized + 'static,
{
Box::new(self)
}
fn get_input_writer(&mut self) -> &mut dyn Write;
fn finish(self) -> io::Result<Self::Out>;
fn finish_boxed(self: Box<Self>) -> io::Result<Self::Out>;
}
mod zstd {
use std::io::{self, Write};
use zstd::stream::{write::Decoder, write::Encoder};
impl<W: Write> super::Coder for Encoder<'static, W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(self) -> io::Result<W> {
self.finish()
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
impl<W: Write> super::Coder for Decoder<'static, W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
self.flush()?;
Ok(self.into_inner())
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
}
mod brotli {
use std::io::{self, Write};
pub use brotli::enc::writer::CompressorWriter;
pub use brotli::writer::DecompressorWriter;
impl<W: Write> super::Coder for CompressorWriter<W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
self.flush().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli encoder failed to finalize stream",
)
})?;
Ok(self.into_inner())
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
impl<W: Write> super::Coder for DecompressorWriter<W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
self.flush().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli decoder failed to finalize stream",
)
})?;
self.into_inner().map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
"brotli decoder failed to finalize stream",
)
})
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
}
mod lzma {
use std::io::{self, Write};
pub use xz2::write::{XzDecoder, XzEncoder};
impl<W: Write> super::Coder for XzEncoder<W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(self) -> io::Result<W> {
XzEncoder::finish(self)
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
impl<W: Write> super::Coder for XzDecoder<W> {
type Out = W;
fn get_input_writer(&mut self) -> &mut dyn Write {
self
}
fn finish(mut self) -> io::Result<W> {
XzDecoder::finish(&mut self)
}
fn finish_boxed(self: Box<Self>) -> io::Result<W> {
self.finish()
}
}
}
fn run_example<OutEncode, OutDecode>(
mut encoder: Box<dyn Coder<Out = OutEncode>>,
mut decoder: Box<dyn Coder<Out = OutDecode>>,
) where
OutEncode: Write + std::fmt::Debug + Deref<Target = [u8]>,
OutDecode: Write + Deref<Target = [u8]>,
{
// Encode
encoder
.get_input_writer()
.write_all(b"Hello world!")
.unwrap();
let output = encoder.finish_boxed().unwrap();
println!("{:?}", output);
// Decode
decoder.get_input_writer().write_all(&output).unwrap();
let output = decoder.finish_boxed().unwrap();
println!("{:?}", String::from_utf8_lossy(&output));
}
fn main() {
println!("zstd:");
run_example(
::zstd::stream::write::Encoder::new(Vec::new(), 0)
.unwrap()
.into_boxed_coder(),
::zstd::stream::write::Decoder::new(Vec::new())
.unwrap()
.into_boxed_coder(),
);
println!();
println!("brotli:");
run_example(
::brotli::enc::writer::CompressorWriter::with_params(Vec::new(), 1024, &Default::default())
.into_boxed_coder(),
::brotli::writer::DecompressorWriter::new(Vec::new(), 1024).into_boxed_coder(),
);
println!();
println!("lzma:");
run_example(
::xz2::write::XzEncoder::new(Vec::new(), 5).into_boxed_coder(),
::xz2::write::XzDecoder::new(Vec::new()).into_boxed_coder(),
);
println!();
}
zstd:
[40, 181, 47, 253, 0, 88, 97, 0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]
"Hello world!"
brotli:
[139, 5, 128, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 3]
"Hello world!"
lzma:
[253, 55, 122, 88, 90, 0, 0, 4, 230, 214, 180, 70, 2, 0, 33, 1, 22, 0, 0, 0, 116, 47, 229, 163, 1, 0, 11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 0, 10, 99, 214, 243, 246, 128, 91, 211, 0, 1, 36, 12, 166, 24, 216, 216, 31, 182, 243, 125, 1, 0, 0, 0, 0, 4, 89, 90]
"Hello world!"