Struct fourleaf::stream::Stream
[−]
[src]
pub struct Stream<R> { /* fields omitted */ }
Streaming fourleaf parser and encoder.
The parser is built around pulling one tag/value pair at a time via
next_field()
. While it automatically handles the format of tag/value
pairs and the special descriptors, it is unaware of the tree structure of
the document. For example, it will happily parse an infinite byte stream of
EndOfStruct
values.
The reader used as input should be buffered if it is based on a heavyweight resource like a file or socket handle, as many decoding operations will read exactly one byte.
The position of the underlying reader is always immediately after the last
content read, unless any method call returns an Error
, in which case the
exact position is unspecified and continued use of the stream will not
result in well-defined results.
Methods
impl<T: AsRef<[u8]>> Stream<TransparentCursor<T>>
[src]
fn from_slice(t: T) -> Self
Create a new stream which decodes the given slice.
To use the most flexible zero-copy APIs, t
should be a &[u8]
.
impl<R> Stream<R>
[src]
fn new(inner: R) -> Self
Create a new stream starting from byte offset 0.
fn new_seek(inner: R) -> Self where
R: Seek,
R: Seek,
Like new()
, but if the stream needs to skip a blob, it will use
seek()
instead of reading and discarding data.
Once specialisation becomes stable, this method will likely be
deprecated as detecting to use seek()
will be determined
automatically.
fn commit(&mut self) -> Result<()>
Ensures the Stream
is in a fully consistent state.
It is usually not necessary to call this except in very particular
circumstances before closing a write stream, or when performing
operations at a level lower than the Stream
abstraction.
Calls to Stream
which read or write data will implicitly commit
changes that occurred before that call.
fn into_inner(self) -> R
Consumes this Stream
and returns the underlying byte stream.
The byte stream is simply returned at whatever its current position is,
which could be inside a blob. Use commit()
to ensure the stream is
positioned on a field boundary if that is desired.
fn get_ref(&self) -> &R
Borrows a reference to the underlying byte stream.
This is mainly intended for things like syncing a file handle. If the
intent is to do things that depend on the stream position, consider
whether commit()
should be called (depending on whether being in the
middle of a blob is reasonable/desired). If the use of the byte stream
causes the stream to be repositioned, ensure that set_pos()
is later
called to inform the Stream
of this fact.
fn get_mut(&mut self) -> &mut R
Borrows a reference to the underlying byte stream.
This is mainly intended for things like syncing a file handle. If the
intent is to do things that depend on the stream position, consider
whether commit()
should be called (depending on whether being in the
middle of a blob is reasonable/desired). If the use of the byte stream
causes the stream to be repositioned, ensure that set_pos()
is later
called to inform the Stream
of this fact.
fn pos(&self) -> u64
Returns the current byte offset of the stream.
fn set_pos(&mut self, pos: u64)
Changes the stream's current conception of the position in the byte stream.
This should only be used if some operation outside the Stream
's
control caused the position of the byte stream to actually change
(e.g., via use of get_mut
), as the stream will assume that other
positions it maintains are still valid. It may also be used immediately
after construction to change the starting offset value.
To change the logical position in the byte stream, use reset_pos()
instead.
fn reset_pos(&mut self, pos: u64) -> Result<()>
Alters what this stream considers to be the logical position in the byte stream.
This will cause the stream to flush any operations depending on the current position, and so can encounter IO errors.
fn seek(&mut self, whence: SeekFrom) -> Result<u64> where
R: Seek,
R: Seek,
Repositions the Stream
according to whence
.
This is not std::io::Seek
because it has somewhat different
semantics; in particular, the stream's current position may be changed
by this call before the seek operation itself is applied, and the
operation will be applied relative to that position.
It is the caller's responsibility to ensure that the new location is sensible; i.e., that the byte location points to a descriptor in the underlying byte stream.
This resets the struct depth counter to 0. If this is not correct, it
is the callers responsibility to call set_struct_depth
to the correct
value if features depending on struct depth tracking are being used.
The Stream
's own pos
is set to match what the underlying byte
stream returns. If the client code is using a logical pos
which
differs from the underlying stream position, the caller will need to
fix the discrepancy by calling reset_pos()
afterwards.
fn eof(&self) -> bool
Returns whether an EndOfDoc
descriptor has been encountered.
If this returns true, next_field()
will always return None
.
fn clear_eof(&mut self)
Clears the EOF flag if it had been set by an EndOfDoc
descriptor,
allowing the stream to continue with whatever follows.
fn graceful_eof(&self) -> bool
Returns whether graceful EOF handling is enabled.
See set_graceful_eof()
for an explanation.
fn set_graceful_eof(&mut self, graceful_eof: bool)
Sets whether an EOF where a descriptor is expected should be handled gracefully.
If true, if an EOF is encountered when reading a descriptor (i.e., the
start of a field), the stream acts as if it had encountered an
explicit EndOfDoc
descriptor and returns None
from next_field()
and sets the EOF flag.
If false, encountering an EOF when reading a descriptor results in an
UnexpectedEof
error.
The default is false; i.e., inputs are expected to be explicitly terminated. Setting it to true is useful when working with append-only files which necessarily cannot have explicit termination.
fn struct_depth(&self) -> u64 where
R: Read,
R: Read,
Returns the current struct nesting depth of this stream.
This specifically counts the number of EndOfStruct
elements required
to return to top-level. If the input causes the counter to overflow, it
simply saturates at 0.
Initially, the struct depth is set to 0. Upon reading a field of any
kind, it becomes 1. Struct
and Enum
fields further increment this
value, and corresponding EndOfStruct
elements decrement it.
EndOfDoc
elements immediately set it to 0.
Stream
does not guarantee any particular behaviour if this counter
overflows. Note that this is normally impossible, since such an input
would also need to be greater than the maximum input length Stream
can handle.
The struct depth is only tracked for read operations, since it is
intended for recovering from errors or skipping unknown items. For this
reason the Read
constraint is present, even though this call itself
does not do any IO.
fn set_struct_depth(&mut self, depth: u64)
Resets the struct depth counter.
Generally, the only reason to call this is if the caller caused the position of the underlying stream to change and wishes to correct the counter, or in other extraordinary circumstances.
fn skip_up(&mut self, depth: u64) -> Result<()> where
R: Read,
R: Read,
Decodes and discards input elements until the struct nesting depth is less than or equal to the given depth or an error occurs.
This can be used to easily skip unknown fields, or to handle recoverable errors by moving to the next top-level item.
See struct_depth
for details on how struct depth is tracked.
fn next_field(&mut self) -> Result<Option<Field<R>>> where
R: Read,
R: Read,
Decodes the next field.
If the end of the current struct has been reached, returns None
, but
the next call will continue parsing the input. If the end of the
document is reached, returns None
without doing IO; this can be
tested explicitly with the eof()
method.
Padding is implicitly skipped.
If an exception descriptor is encountered, up to 256 bytes of the message are read, converted to a string lossily, and returned as an error. Subsequent calls would continue in the stream immediately after the error message.
If the field is a blob, it is not read in by this call. If the caller
does not fully consume such a blob itself, the next call to
next_field
will do so.
If you want to use padding or exceptions as in-band signalling, see
next_element()
instead.
fn next_element(&mut self) -> Result<Element<R>> where
R: Read,
R: Read,
Reads the next element from the stream.
This is lower-level than next_field()
, since will return padding,
does not convert exceptions to errors, and distinguishes between
end-of-struct and end-of-document conditions.
If the eof()
flag is set, this returns Element::EndOfDoc
without
reading anything.
If this call returns Element::EndOfDoc
, the eof()
flag is
implicitly set.
fn write_null(&mut self, tag: u8) -> Result<()> where
R: Write,
R: Write,
Writes a field with the null/unit value to the output, i.e., a zero.
Panics
Panics if tag
is not a valid field tag.
fn write_u64(&mut self, tag: u8, n: u64) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_u8(&mut self, tag: u8, n: u8) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_i8(&mut self, tag: u8, n: i8) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_u16(&mut self, tag: u8, n: u16) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_i16(&mut self, tag: u8, n: i16) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_u32(&mut self, tag: u8, n: u32) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_i32(&mut self, tag: u8, n: i32) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_i64(&mut self, tag: u8, n: i64) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_usize(&mut self, tag: u8, n: usize) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_isize(&mut self, tag: u8, n: isize) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given integer value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_bool(&mut self, tag: u8, b: bool) -> Result<()> where
R: Write,
R: Write,
Writes a field with the given boolean value to the output.
Panics
Panics if tag
is not a valid field tag.
fn write_blob_data<D: AsRef<[u8]>>(
&mut self,
tag: u8,
data: D
) -> Result<Blob<R>> where
R: Write,
&mut self,
tag: u8,
data: D
) -> Result<Blob<R>> where
R: Write,
Writes a blob field with the given byte content to the output.
The new blob is returned, positioned at the end. The caller is free to
seek on the blob, but must restore the position to the end before
attempting to continue using the Stream
.
Panics
Panics if tag
is not a valid field tag.
fn write_blob_alloc(&mut self, tag: u8, len: u64) -> Result<Blob<R>> where
R: Write,
R: Write,
Writes the header for a blob field with the given length to the output.
The new blob is returned, positioned at the beginning. The caller must
advance the position to the end of the blob and leave the position at
the end before continuing to use the Stream
.
Panics
Panics if tag
is not a valid field tag.
fn write_blob_dynamic(&mut self, tag: u8) -> Result<Blob<R>> where
R: Write + Seek,
R: Write + Seek,
Writes the header for a blob field with unknown length to the output.
The new blob is returned, positioned at the beginning. The caller must
write the desired data to the blob, and then cause the Stream
to be
committed, either by calling commit()
or by using another read or
write function.
This function operates by initially nominally allocating the maximum
possible size for the blob and returning that. When the Stream
commits, it uses the current position to determine the actual size of
the blob, then seeks back to the blob header and writes the real length
in, then seeks back to the end of the blob to continue operation.
Because the length is written after the blob, the length must be in fixed-width format, which may incur up to 9 bytes of overhead. Because of this and of the overhead of multiple seeks, this should only be used for blobs which are not reasonable to buffer otherwise.
It is unspecified what the result is if the caller writes the dynamic blob but then seeks the position to an earlier point of the blob and leaves position there.
Panics
Panics if tag
is not a valid field tag.
fn write_struct(&mut self, tag: u8) -> Result<()> where
R: Write,
R: Write,
Writes a struct field to the output.
The body of the struct can be constructed by continuing to make calls
to the write_*
methods of this Stream
, and terminating with the
write_end_struct
method.
Panics
Panics if tag
is not a valid field tag.
fn write_enum(&mut self, tag: u8, discriminant: u64) -> Result<()> where
R: Write,
R: Write,
Writes an enum field to the output.
The body of the enum can be constructed by continuing to make calls to
the write_*
methods of this Stream
, and terminating with the
write_end_struct
method.
Panics
Panics if tag
is not a valid field tag.
fn write_end_struct(&mut self) -> Result<()> where
R: Write,
R: Write,
Writes an end-of-struct element to the output.
fn write_end_doc(&mut self) -> Result<()> where
R: Write,
R: Write,
Writes an end-of-document element to the output.
fn write_exception_data<D: AsRef<[u8]>>(&mut self, data: D) -> Result<Blob<R>> where
R: Write,
R: Write,
Writes an exception to the output whose content is the given byte slice.
The semantics of the blob itself are the same as for write_blob_data
.
fn write_exception_alloc(&mut self, len: u64) -> Result<Blob<R>> where
R: Write,
R: Write,
Writes the header for an exception with the given data length to the output.
The semantics of the blob itself are the same as for
write_blob_alloc
.
fn write_exception_dynamic(&mut self) -> Result<Blob<R>> where
R: Write + Seek,
R: Write + Seek,
Writes the header for an exception whose data length is unknown to the output.
The semantics of the blob itself are the same as for
write_blob_dynamic
.
fn write_padding(&mut self) -> Result<()> where
R: Write,
R: Write,
Writes a padding element to the output.
fn pad_to_align(&mut self, align: u64) -> Result<()> where
R: Write,
R: Write,
Writes padding bytes to the output until the position of this Stream
is a multiple of alignment
.
If the position is already a multiple of alignment
, nothing is
written, but the effect of a call to commit()
happens regardless.
alignment
must be a power of two.
fn write_element<I>(&mut self, e: &mut Element<I>) -> Result<()> where
R: Write,
I: Read,
R: Write,
I: Read,
Writes the given element to this stream.
This is useful for copying from one Stream
to another. For other
uses, prefer calling the direct functions instead of constructing
Element
s programatically.
fn write_field<I>(&mut self, f: &mut Field<I>) -> Result<()> where
R: Write,
I: Read,
R: Write,
I: Read,
Writes the given field to this stream.
This is useful for copying from one Stream
to another. For other
uses, prefer calling the direct functions instead of constructing
Field
s programatically.