Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoder: StreamWriter not an io::Write #279

Open
scurest opened this issue Jan 23, 2021 · 1 comment
Open

encoder: StreamWriter not an io::Write #279

scurest opened this issue Jan 23, 2021 · 1 comment

Comments

@scurest
Copy link
Contributor

scurest commented Jan 23, 2021

I don't think StreamWriter is actually a std::io::Write because the docs for write say

A call to write represents at most one attempt to write to any wrapped object. [...]
If an error is returned then no bytes in the buffer were written to this writer.

and looking at write...

image-png/src/encoder.rs

Lines 460 to 476 in 26f8f8b

fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
let written = buf.read(&mut self.curr_buf[self.index..])?;
self.index += written;
if self.index >= self.curr_buf.len() {
let filter_type = filter(
self.filter,
self.adaptive_filter,
self.bpp,
&self.prev_buf,
&mut self.curr_buf,
);
self.writer.write_all(&[filter_type as u8])?;
self.writer.write_all(&self.curr_buf)?;
mem::swap(&mut self.prev_buf, &mut self.curr_buf);
self.index = 0;
}

First buf always makes it into self.curr_buf even if one of the write_all calls errors. Second two write_alls is at least two writes to the wrapped writer and one write might make it to the writer, but a second write might error.

@HeroicKatora
Copy link
Member

HeroicKatora commented Jan 23, 2021

That seems partially right. The 'at most one write' is not a hard requirement and it's not entirely clear either. See in particular this issue: rust-lang/rust#56889.

However, I very much agree on the odd behavior of partial effect on error.

  • The changes to index could be reverted when the write call fails, which virtually also reverts the write to buf.
  • There could be a spare byte at the start where the filter_type can be written which would make it possible to do a single write call, even without using vector IO.
  • Using even one write_all is not a single write, as it internally loops! The type would have to keep state for the case where the previous scanline was already filtered but only partially written, and it needs to be flushed before allowing the continuation. However here we run into the same issue as referenced above as we can't reasonably return 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants