io::IReader
The interface IReader
is the counterpart of io::IWriter and an abstraction to read
chunks of bytes with variable length from a data channel.
Public API
/**
* Returns the maximum number of bytes that may be read in one peek call
*/
virtual size_t maxSize() const = 0;
/**
* Returns a slice to the next piece of available data.
* \return - Slice of bytes if underlying queue was not empty
* - Empty slice otherwise
*/
virtual ::estd::slice<uint8_t> peek() const = 0;
/**
* Releases the memory that the last peek() call returned.
*
* Calling release() makes a new call to peek() mandatory! The previously peeked data must not
* be used anymore.
*/
virtual void release() = 0;
Usage of API
The next sequence diagram visualizes the two step peek()
and release()
API. After a call to peek()
returns a slice of data with size greater than zero, the user can consume this data. A call
to release()
frees the data again, also invalidating it for the user.
It must not be used anymore after calling release()
.
Example
/**
* Tries to receive a CanFrame from a given IReader.
* \param frame CanFrame to receive to, i.e. frame provides memory to copy to.
* \param reader IReader to try to receive a frame from.
* \return true if a frame was read, false otherwise.
*/
bool receiveCanFrame(CanFrame& frame, ::io::IReader& reader)
{
auto data = reader.peek();
if (data.size() < sizeof(uint32_t))
{
// No frame available (A frame consists of at least uint32_t id)
return false;
}
// Copy data to frame. We expect a big endian 32bit id followed by the actual data.
frame.id = ::estd::memory::take<::estd::be_uint32_t>(data);
::estd::memory::copy(frame.data, data);
frame.data.trim(data.size());
// Release data to channel.
reader.release();
return true;
}