pub struct FetchObjectWriter {
group_order: GroupOrder,
prior_location: Option<(u64, u64)>,
prior_subgroup_id: Option<u64>,
prior_publisher_priority: Option<u8>,
}Expand description
Re-encodes resolved fetch frames onto one FETCH stream.
The exact inverse of FetchObjectReader, and it exists for one caller:
something that has read a stream and is writing a different stream from the
same frames. Removing a frame changes what the frames after it are encoded
against, and draft-21 Section 11.4.1.1 defines nearly every field against
“the prior Object”, so the survivor that follows a removed run cannot keep
its original bytes. What has to change is not one field: an Object that
carried no Group ID Delta because it shared its predecessor’s group needs
one once that predecessor is gone, so a field appears and a flag bit with
it.
§Why this is not a general encoder
Every frame it writes came off a stream, so the caller already holds the
frame’s own FetchObjectHeader alongside the resolved values. That header
is used as the preference: wherever the original shape still encodes the
same meaning against the new predecessor, it is kept, so a stream with
nothing removed from it is reproduced byte for byte. Only where the original
shape would now decode to something else is a different one chosen. An
encoder built from the resolved values alone could not do that — it would
have to invent a canonical form and would rewrite every frame on a stream
that needed no rewriting at all.
§What it refuses
CodecError::InvalidField where no encoding exists rather than picking
one: a Group ID that moves against the FETCH’s Group Order, an Object ID
that does not advance, an Object with neither a Subgroup ID nor the Datagram
bit, and the arithmetic overflows. Each of these is a frame this writer was
handed that no draft-21 stream could carry, and inventing a value for it
would put a different Object on the wire than the one it was given.
Fields§
§group_order: GroupOrder§prior_location: Option<(u64, u64)>Group ID and Object ID of the last frame written, marker or Object.
prior_subgroup_id: Option<u64>Subgroup ID of the last actual Object written that had one.
prior_publisher_priority: Option<u8>Publisher Priority of the last actual Object written.
Implementations§
Source§impl FetchObjectWriter
impl FetchObjectWriter
Sourcepub fn new(group_order: GroupOrder) -> Self
pub fn new(group_order: GroupOrder) -> Self
A writer for a stream whose Groups are being written in group_order.
The order has to match the one the FETCH was opened with, for the same
reason FetchObjectReader::new takes it: it decides whether a Group
ID Delta adds or subtracts, and it is not on the data stream.
Sourcepub fn header_for(
&self,
frame: &FetchObject,
) -> Result<FetchObjectHeader, CodecError>
pub fn header_for( &self, frame: &FetchObject, ) -> Result<FetchObjectHeader, CodecError>
The header that encodes frame against everything written so far.
Does not advance the writer — Self::write_object_header is the call
that does both. Separated so that a caller can measure the bytes a
re-encode would take before committing to it.
§Errors
CodecError::InvalidField for a frame that cannot be encoded against
the current predecessor; see the type’s own documentation for the list.
Sourcefn identity_fields(
&self,
frame: &FetchObject,
original: &FetchObjectHeader,
) -> Result<(Option<VarInt>, Option<VarInt>), CodecError>
fn identity_fields( &self, frame: &FetchObject, original: &FetchObjectHeader, ) -> Result<(Option<VarInt>, Option<VarInt>), CodecError>
The Group ID Delta and Object ID Delta fields, as this predecessor needs them.
Presence is forced by the frame rather than chosen: a group that differs from the predecessor’s has to be stated, and one that matches has to be left off, since a delta of zero means the next group along and not this one. Only the Object ID Delta has a choice to make, and it is made in favour of the shape the frame arrived in.
Sourcefn subgroup_field(
&self,
frame: &FetchObject,
original: &FetchObjectHeader,
) -> Result<(u64, Option<VarInt>), CodecError>
fn subgroup_field( &self, frame: &FetchObject, original: &FetchObjectHeader, ) -> Result<(u64, Option<VarInt>), CodecError>
The Subgroup ID mode bits and the explicit field, if one is needed.
The frame’s own mode is tried first, so a run of Objects that inherited their Subgroup ID keeps inheriting it and its bytes do not move. Only when the predecessor changed under it does a different mode get chosen, and then the cheapest one that says the right number.
Sourcefn priority_field(
&self,
frame: &FetchObject,
original: &FetchObjectHeader,
) -> Result<Option<u8>, CodecError>
fn priority_field( &self, frame: &FetchObject, original: &FetchObjectHeader, ) -> Result<Option<u8>, CodecError>
The Publisher Priority field, or None when the predecessor already
carries it.
Written whenever the frame wrote one, so a publisher that stated a priority on every Object keeps its bytes, and written anyway when the predecessor’s differs or when there is no predecessor to inherit from.
Sourcepub fn write_object_header(
&mut self,
frame: &FetchObject,
out: &mut impl BufMut,
) -> Result<FetchObjectHeader, CodecError>
pub fn write_object_header( &mut self, frame: &FetchObject, out: &mut impl BufMut, ) -> Result<FetchObjectHeader, CodecError>
Encode frame against everything written so far and advance.
Writes the header only. The payload is frame.header.payload_length
bytes and is the caller’s to copy, unchanged — nothing about it depends
on what preceded the Object.
§Errors
CodecError::InvalidField for a frame with no encoding against the
current predecessor. The writer is left untouched when this happens, so
a caller that gives up on one frame and carries on with the next is
writing against the same predecessor it thought it was.
Sourcepub fn advance(&mut self, frame: &FetchObject)
pub fn advance(&mut self, frame: &FetchObject)
Record frame as the predecessor of whatever is written next.
Split from the write so that a caller re-emitting bytes it already holds can advance without producing a header twice — which is what happens whenever the framing a frame arrived in still encodes the same meaning against the frame before it, and is why this is public.