Conversation
The provided encode methods on Message and ViewEncode now compute the exact size, then write any BufMut into that many contiguous bytes of its spare capacity through a shared bounds-checked cursor (PreSized). Each message's write_to is compiled once for all BufMut sinks instead of once per sink type, and encoding into a BytesMut with room no longer makes a call per tag and varint byte. A sink with less room than the message is filled through a scratch Vec and appended with one put_slice. Rope and types that implement EncodeSink without BufMut still receive every write individually. Generated lazy views and DynamicMessage are unchanged. A write_to that produces more bytes than compute_size declared now panics in release builds too, and in debug builds one that produces fewer panics in every encode entry point.
A `Table<M>` describes a message as a sorted array of twelve-byte entries (field number, byte offset, and a kind giving the field type and cardinality). One set of interpreters, shared by every message, sizes, writes and decodes a message from its table, so a message costs a table rather than three per-field code sequences. The interpreters cover scalars, strings, bytes, enums, messages and their repeated and packed forms, with unknown-field preservation. They follow the unrolled code's wire format, two-pass size protocol, and recursion, unknown-field and element-memory limits. Encoding into any `BufMut` runs one non-generic function in this crate through the pre-sized cursor; other sinks get an instance generic over the sink. `Table::new` is `unsafe`, because offsets and kinds must describe the struct's layout, and checks the rest of the table's structure (order, aux indexes and variants, the dense lookup) at compile time when it initialises a static.
|
All contributors have signed the CLA ✍️ ✅ |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
buffa::table, the runtime for the table-drivenMessagecodec proposed in #463: a#[doc(hidden)]module that sizes, writes, and decodes a message from a staticTable<M>of 12-byte field entries. Nothing calls it yet; the generator that emits tables is #469.Stacked on #467, whose pre-sized cursor the encode interpreter writes through, and adds a
#[doc(hidden)]EncodeSink::__with_pre_sizedfor it.Kindis the field type crossed with its cardinality, so the interpreter dispatches once per field. Decoding runs over a contiguous&[u8], gathering a non-contiguousBufonce.Table::newisunsafe, because its offsets and kinds must describe the struct. Generated code builds tables only through the exported__table!and__table_entry!macros, which hold theunsafeblock, take each offset fromoffset_of!, and require the field's type to equal the type its kind stores. A wrong kind is a compile error, and generated code compiles under#![forbid(unsafe_code)]. A new CI step runs the module's tests under Miri.Table::newalso compares anABIconstant, so tables from a different codegen version fail to build.Deviation from #463, which proposed a
buffacargo feature for theunsafe: there is none, because theunsafeblock is inside the macros.offset_of!needs Rust 1.77, so on the 1.75 MSRV__table!expands to acompile_error!naming the version.Behaviour that differs from unrolled code, listed in the module docs: a length past the end of its enclosing message fails at once with
UnexpectedEof,Table::merge_fieldneeds a contiguous buffer (so the type of a group field cannot be a table message), andclear()resets toDefault, releasing allocations.About 2,400 lines are outside
tests.rs, well over the 250-line guideline: the interpreters, the macros that make them sound, and the Miri tests that check them are not usable or checkable apart.