A GVariant stream is a stream of GVariant values (of a given type) as could be sent over a socket or streamed to and from disk. Each GVariant value is complete and properly aligned. A complete value can be taken off the wire as soon as it is fully transmitted.
This is, in effect, a way of turning a stream socket into a sequence of GVariant "packets".
As with GVariant, there is no theoretical limitation to the sizes of packets that can be transmitted. Implementations, however, may not support packets past a given size (typically half of the addressable virtual memory).
Communication can occur in one direction or both directions. For bidirectional sockets, communication in each direction is independent.
The peers must have agreed upon the "packet type", which is the GVariant type of each "packet". The peers must also have agreed on an endianness for the packets or a mechanism for determining endianness by inspecting the packets.
Each packet consists of the transmission of the size of the packet, followed immediately by the packet data, followed by adding if required. The padding is not included in the size of the packet.
The packet data is always properly aligned, according to the requirements of its type.
The size is transmitted as one or more unsigned words, in little endian. The word size is chosen to be equal to the alignment requirement of the packet type. For example, if the GVariant data had an alignment requirement of 4 then a word size of 32bits would be used. If the GVariant data has no alignment requirement then the word size is a single byte. The words are fully-aligned according to their type (which is why padding may need to be added after the packet data).
If the upper bit of a word is set then it is an indication that another word follows. The lower bits of the current word are taken together with the higher bits of the following words until a word is encountered that does not have its high bit set. This "little endian" approach is always used, regardless of the endianness of the packets being sent.
The minimal representation must be used. It is not permitted to encode sizes that would fit into a smaller number of words into a larger number of words.
Because the word size is equal to the alignment requirement of the packet data and because a whole number of words is sent, and because packets are padded afterwards to reestablish alignment, the words and the packets will always fall on proper natural alignment.
The variable-width size field is a potentially annoying implementation detail, but it is easy to deal with in almost any situation.
The primary concern is using a naive approach of reading a single byte at a time (via a syscall) in order to determine the size. This can always be avoided.
If the code reading the sizes is also responsible for creating the values then it can simply over-read the size and then apply the 'excess' to the start of the created value.
For any case where the data is mapped into memory, it can be directly inspected in an efficient way.
When using IO buffered in user-space, it is always possible to 'peek' the buffer.
For any case where the data is backed by a seekable stream and the API is such that a size is queried out of the stream and then a separate piece of code reads the value, it is expected that implementations will speculatively over-read in order to acquire the maximum number of bytes that are needed to represent the maximum size supported by the implementation. The stream can then be seek()ed back to the correct position. It is also possible to use pread().
If the stream is a socket then it is expected that implementations will use MSG_PEEK in order to speculatively over-read, as above.
Additionally, in many cases, the implementation may know that only a single word is ever reasonable. This will pretty much always be the case when the alignment requirement is equal to or greater than the system pointer size (since any other case would require more than half of the available virtual memory to handle).