Trait netio::BufReadGrow [] [src]

pub trait BufReadGrow: BufRead {
    fn grow_buf(&mut self) -> Result<&[u8]>;

    fn read_until2_net(&mut self, delims: (u8, u8), buf: &mut Vec<u8>) -> Result<()> { ... }
    fn skip_until2_net(&mut self, delims: (u8, u8)) -> Result<()> { ... }
    fn fill_buf_str(&mut self) -> Result<&str> { ... }
    fn grow_buf_str(&mut self) -> Result<&str> { ... }
    fn read_to_string_net(&mut self, buf: &mut String) -> Result<()> { ... }
    fn read_line_net(&mut self, buf: &mut String) -> Result<()> { ... }
    fn chars_net(self) -> Chars<Self> where Self: Sized { ... }
}

A BufReadGrow is a BufReader that has the ability to read additional data even if the buffer is not empty.

A BufRead guarantees an internal buffer of at only one byte with no possibility to read additional data without consuming the already read data first. With this limitation it is not possible to implement many functions in an interrupt-safe way.

Interrupt-safe function require that - when the function returns - all data is either left in the stream or appended to the buffer. But for example when read UTF-8 with a BufReader, this requirement can only be met by appending incomplete UTF-8 to the buffer which is also unacceptable by itself.

For that reason, the BufReadGrow trait is introduced which extends BufRead by a method to grow the internal buffer. This requires the buffer to be able to relocate the data in the internal buffer.

Required Methods

fn grow_buf(&mut self) -> Result<&[u8]>

Grows the internal buffer of this object by at least one byte, returning the buffer contents.

Like BufRead::fill_buf, this function is a lower-level call. It needs to be paired with the consume method to function properly. When calling this method, none of the contents will be "read" in the sense that later calling read may return the same contents. As such, consume must be called with the number of bytes that are consumed from this buffer to ensure that the bytes are never returned twice.

Calling this function will either extend the current buffer size by at least one byte, or else return an error of kind ErrorKind::UnexpectedEof.

Errors

This function will return an I/O error if the underlying reader was read, but returned an error or if the underlying reader was already at EOF.

Provided Methods

fn read_until2_net(&mut self, delims: (u8, u8), buf: &mut Vec<u8>) -> Result<()>

Read all bytes into a buffer until two consecutive delimiters are reached.

This function will read bytes from the underlying stream and push them to the specified buffer buf, until the two consecutive delimiters delims are found. If the delimiters are found, they also part of the result.

Errors

This function will return an error immediately if a call to fill_buf returns any kind of error. Instances of ErrorKind::Interrupted are not handled by this function.

If this reader has reached EOF then this function will return ErrorKind::UnexpectedEof.

In case of an error, all bytes read up to that point are appended to the buffer and consumed from this buffered reader. There's one notable exception to that rule: If the last byte in the buffer would be the first delimiter, it is left in the buffered reader. Otherwise retrying on error would not work reliably.

In any case, all bytes consumed from the buffered reader will be written to the specified buffer and vice versa. It is guaranteed that no data is lost in case of error.

fn skip_until2_net(&mut self, delims: (u8, u8)) -> Result<()>

Skip all bytes until two consecutive delimiters are reached.

This function will discard bytes from the underlying stream until the two consecutive delimiters delims are found.

Errors

This function will return an error immediately if a call to fill_buf returns any kind of error. Instances of ErrorKind::Interrupted are not handled by this function.

If this reader has reached EOF then this function will return ErrorKind::UnexpectedEof.

fn fill_buf_str(&mut self) -> Result<&str>

Fills the internal buffer of this object, returning the buffer content as a string

This function will return at least one valid char except when reaching EOF. If invalid or incomplete UTF-8 is encountered, the function returns all valid UTF-8 up to that point.

If the function returns an empty slice, the unterlying reader has reached EOF and all data in the stream was valid UTF-8.

Errors

  • If either fill_buf or grow_buf return an error, this error is returned immediately.
  • If invalid UTF-8 is encountered at the beginning of the buffer, an error of kind ErrorKind::InvalidData is returned.
  • If an incomplete UTF-8 character followed by EOF is encountered at the beginning of the buffer, an error of kind ErrorKind::UnexpectedEof is returned.

Issues

Currently there's no way to decide if the remaining data is an incomplete UTF-8 char or just plain invalid UTF-8 if the remaining buffer is smaller or equal than 4 bytes. (Issue rust-lang/rust#32584)

This case is currently just interpreted as ErrorKind::UnexpectedEof.

fn grow_buf_str(&mut self) -> Result<&str>

Grows the internal buffer of this object by at least one char, returning the buffer content as a string

This function will return at least one additional valid char compared to a call to fill_buf_str. If invalid or incomplete UTF-8 is encountered, the function returns all valid UTF-8 up to that point.

If the function returns an empty slice, the unterlying reader has reached EOF and all data in the stream was valid UTF-8.

Errors

  • If either fill_buf or grow_buf return an error, this error is returned immediately.
  • If invalid UTF-8 is encountered at the beginning of the buffer s.t. no additional char can be returned, an error of kind ErrorKind::InvalidData is returned.
  • If EOF is encountered, such that no additional char can be returned, an error of kind ErrorKind::UnexpectedEof is returned.

Issues

Currently there's no way to decide if the remaining data is an incomplete UTF-8 char or just plain invalid UTF-8 if the remaining buffer is smaller or equal than 4 bytes. (Issue rust-lang/rust#32584)

This case is currently just interpreted as ErrorKind::UnexpectedEof.

fn read_to_string_net(&mut self, buf: &mut String) -> Result<()>

Read all bytes until EOF in this source, placing them into a string.

This function will continuously call fill_buf/grow_buf and consume to append more data to buf until fill_buf returns either Ok(&[]) or any kind of error occurs.

Errors

This function will return an error immediately if any call to fill_buf or grow_buf returns any kind of error. Instances of ErrorKind::Interrupted are not handled by this function.

If invalid UTF-8 is encountered, an error of kind ErrorKind::InvalidData is returned and the string will contain all valid UTF-8 up to that point.

All bytes consumed from the reader will be written to the buffer and vice versa. It is guaranteed that no data is lost in case of error.

Differences to std::io::Read::read_to_string

  • Does not retry on ErrorKind::Interrupted.
  • Uses BufReadGrow instead of BufRead.
  • Does not return the number of bytes that are copied.
  • On error, string will contain all valid UTF-8 up to that point.

Advantages

  • Function is interruptable, e.g. to allow graceful shutdown for server applications.
  • No data ist lost on error (e.g. invalid UTF-8).

Disadvantages

The fact that it does not return the number of bytes copied stems from the fact that it cannot return this information in case of error. This would go against the goal of allowing reliable retry.

fn read_line_net(&mut self, buf: &mut String) -> Result<()>

Read all bytes until a CRLF is reached, and append them to the provided buffer.

This function will UTF-8 characters from the underlying stream and append them to the 'buf' until the CRLF delimiter (the 0xA 0xD bytes) is found.

Errors

Like read_until2_net, this function will return an error immediately if a call to fill_buf returns any kind of error. Instances of ErrorKind::Interrupted are not handled by this function.

This function will return an error of kind ErrorKind::InvalidData if the read bytes are not valid UTF-8. If EOF is reached, an error of kind ErrorKind::UnexpectedEof is returned.

If any kind of error occurs, the buffer will contain all valid UTF-8 up to that point.

In any case, all bytes consumed from the buffered reader will be written to the specified buffer and vice versa. It is guaranteed that no data is lost in case of error.

The read buffer will never contain a CR (\r) as last character, even in case of error. Doing so could lead to skipping a CRLF sequence in case of retry. In case of ErrorKind::UnexpectedEof, this behavior is a bit unexpected and may change in a future version.

Differences to std::io::BufRead::read_line

  • Does not retry on ErrorKind::Interrupted.
  • Does not return the number of bytes that are read.
  • Returns an error on EOF instead of success.
  • Uses CRLF as line ending convention instead of just LF.

Advantages

  • Function is interruptable, e.g. to allow graceful shutdown for server applications.
  • Suitable for network protocols, because those usually use CRLF as line endings.

Disadvantages

The fact that it does not return the number of bytes copied stems from the fact that it cannot return this information in case of error. This would go against the goal of allowing reliable retry.

fn chars_net(self) -> Chars<Self> where Self: Sized

Transforms this reader to an Iterator over chars.

Similar to std::io::Read::chars, this adaptor will attempt to interpret this reader as a UTF-8 encoded sequence of characters. The returned iterator will return None once EOF is reached for this reader. Otherwise each element yielded will be a io::Result<char>.

Errors

In any call to fill_buf or grow_buf returns any kind of error, this error is yielded by the iterator. If invalid UTF-8 is encountered an error of kind ErrorKind::InvalidData is yielded. If the stream is reaching EOF in the middle of an otherwise valid UTF-8 characters, an error of kind ErrorKind::UnexpectedEof is yielded.

Errors of kind ErrorKind::Interrupted are not handled by the iterator itself but treated as any other kind of error. In case of an error, the iterator will not skip any data. Iterating further will simply retry the failed operation.

Note: Ignoring errors will most likely "end" in an endless loop

Differences to std::io::Read::Chars

Issues

Currently there's no way to decide if the remaining data is an incomplete but otherwise valid UTF-8 char or just plain invalid UTF-8. (Issue rust-lang/rust#32584)

Implementors