Я использовал Brotly-sys, но он кажется необслуживаемым. Поэтому я использую Brotli. Я делаю интерфейс для сжатия и распаковки (я также использую lzma и zstd):
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()
}
}
Но получить
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<(), _>`
Но функция flush
не реализует черту Write
.
Coder
интерфейс здесь: https://github.com/Ludea/speedupdate-rs/blob/master/lib/src/codecs/mod.rs#L21
Итак, как я могу исправить мою проблему? (Я могу предоставить репозиторий GH с этой проблемой) Я получаю эту проблему на MacOS/Win64/Linux x86_64. Спасибо
Я обновляю свой пост, чтобы предоставить исходный код Coder
CompressorWriter
, если он стоит прямо сейчас, не совместим с вашим Coder
интерфейсом, потому что он не держит внутренний буфер. Какова ваша цель с интерфейсом Coder
? Самая большая проблема интерфейса Coder
заключается в том, что возвращаемый тип finish
— это W
, а тип возвращаемого значения get_mut
— тоже W
, что несовместимо с CompressorWriter
. Если я что-то не так понял.
Не могли бы вы опубликовать пример того, как вы будете использовать интерфейс Coder
позже? Я не на 100% понимаю, как он предназначен для использования.
Пожалуйста, не публикуйте ссылки на код, это противоречит правилам Stackoverflow.
Да, я думаю, что ваш Coder
интерфейс неисправен. Возможно, вам придется изменить его.
У вас есть лишний ;
после map_err
в DecompressionWriter
с импл.
Мне нужно удалить черту Write
в get_mut
?
pub trait Coder<W>: io::Write { /// Acquires a mutable reference to the underlying writer /// /// Note that mutation of the writer may result in surprising results if /// this decoder is continued to be used. fn get_mut(&mut self) ; fn finish(self) -> io::Result<W>; fn finish_boxed(self: Box<Self>) -> io::Result<W>; }
Вы можете отредактировать свой вопрос, чтобы включить такую информацию :) Многострочный код плохо форматируется в комментариях
Цитата из вашего репозитория: «Обратите внимание, что мутация писателя может привести к неожиданным результатам, если этот декодер будет продолжать использоваться». - Обратите внимание, что это невозможно, проверка заимствования предотвратит это. В этом весь смысл :)
Ваша черта Coder
несовместима со структурой CompressorWriter
. Возможно, вам придется изменить черту Coder
.
Я предполагаю, что поток Coder
:
Coder
.Write
, вызвав get_mut()
.finish()
и извлеките сжатые данные из возвращаемого значения.Ваш признак заставляет возвращаемое значение get_mut()
быть идентичным возвращаемому значению finish()
, что не относится к CompressorWriter
.
Однако для этого вам не нужно вводить новый дженерик; вы можете просто вернуть &mut dyn Write
из вашей get_mut()
функции. Это может потребовать незначительных изменений в других реализациях Coder
, но должно работать.
Небольшое примечание: я переименовал get_mut()
в get_input_writer()
, потому что он конфликтовал с CompressorWriter::get_mut()
, что делало работу с ним намного более раздражающей.
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!"
Пока вы на нем, я бы также изменил некоторые другие вещи для удобства:
into_boxed_coder
для удобства.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!"
Вот более полный пример с реализациями для brotli
, zstd
и 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!"
вы меняете черту Write
на &mut dyn Write
Но я делаю то же самое с zstd.
impl<W: Write> super::Coder<W> for Decoder<'static, W> { fn get_mut(&mut self) -> &mut dyn Write { Decoder::get_mut(self) } fn finish(self) -> std::io::Result<W> { Ok(Decoder::into_inner(self)) } fn finish_boxed(self: Box<Self>) -> io::Result<W> { self.finish() } }
получить expected trait object dyn std::io::Write, found parameter type W
То, как вы реализуете свой Coder for Decoder
, не будет никакого декодирования. Вы напрямую записываете в его выходной буфер, а затем возвращаете весь выходной буфер. Вы в основном обходите весь энкодер. Вам нужно писать в декодер напрямую. Decoder::get_mut
— бесполезная функция для ваших целей. Не просто пробуйте и ошибайтесь, пока API не сделает что-то, на самом деле поймите API, которые вы используете.
@Vana Добавлен пример, включающий реализации для lzma
, brotli
и zstd
. Обратите внимание, что реализация zstd
в вашем репозитории на самом деле ничего не делает, она выполняет нулевое сжатие и просто возвращает ввод. Я переписал его, чтобы он действительно что-то делал. Кроме того, ваша реализация lzma
была намного сложнее, чем нужно; ящик xz2
также предлагает API на основе записи. Я также добавил это.
Работает как положено. Теперь мне нужно реорганизовать main fn для сжатия и распаковки.
Я получаю ^^^^^^ method not found in `Box<dyn codecs::Coder<CheckWriter<W, C>>>` |
при использовании pub fn output_checks(&mut self) -> &mut C { &mut self.writer.writer.get_mut().check }
. Я должен использовать get_input_writer
?
(я обновляю репозиторий GH)
Ну, если вы также изменили get_mut()
на get_input_writer()
, тогда да, вы также должны изменить то, где вы это называете.
Также, пожалуйста, не вставляйте в комментарии многострочный код, он плохо форматируется.
Я получаю no field check on type &mut dyn std::io::Write
, если использую get_input_writer
@Vana может быть актуально: github.com/Speedy37/speedupdate-rs/issues/8
Кажется, оригинальный автор не будет использовать Coder::get_input_writer()
:s
Также получите the trait
codecs::Coder<_>` не реализован для CompressorWriter<W>
на return Ok(BoxCoderDirect::boxed(brotli::CompressorWriter::new(output, 4096, quality, lgwin)));
Stackoverflow не предназначен для чата, он предназначен для одного вопроса и ответа. Если у вас есть новый вопрос, пожалуйста, создайте новый вопрос. По словам автора вашего ящика, мы даже неправильно используем Coder
. Так что я не уверен, ведет ли это обсуждение куда-либо.
Хорошо, отменит все изменения и перезапустится из исходного ящика.
я пробовал :) приветствую
Я успешно переключаюсь на Dropbox Brotli ;)
Пожалуйста, предоставьте источник для
Coder
или простой макет для него.