weida_protocol/datagram.rs
1//! The DATAGRAM payload of a datagram flow: `varint flow || opaque bytes`
2//! (`docs/PROTOCOL.md` §6.9).
3//!
4//! The prefix is a QUIC varint rather than CBOR for the same reason a cursor
5//! record is: it is on the hot path, self-delimiting, and a map header per
6//! datagram would buy nothing the FLOW header does not already say.
7
8use crate::varint::{self, decode_varint};
9
10/// Largest datagram a local transport carries in one FLOW record
11/// (`docs/PROTOCOL.md` §2.1). A longer record is a protocol violation.
12pub const LOCAL_MAX_DATAGRAM: usize = 1200;
13
14/// The varint prefix for flow `flow`, in a fixed buffer, and its length.
15///
16/// # Panics
17///
18/// Above 2^62 − 1, which no flow id reaches: ids are allocated by a counter
19/// per connection and direction.
20pub fn flow_prefix(flow: u64) -> ([u8; varint::MAX_ENCODED_LEN], usize) {
21 let mut out = [0u8; varint::MAX_ENCODED_LEN];
22 let len = varint::write_varint(flow, &mut out).expect("flow ids stay below 2^62");
23 (out, len)
24}
25
26/// Splits a received datagram into its flow id and the offset of its payload.
27///
28/// `None` when the input ends inside the varint. That is not an error: a
29/// truncated datagram is dropped and counted like one for an unknown flow
30/// (`docs/PROTOCOL.md` §6.9).
31pub fn split_flow_datagram(input: &[u8]) -> Option<(u64, usize)> {
32 decode_varint(input).ok()
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38
39 #[test]
40 fn a_prefix_splits_back_to_its_flow_and_offset() {
41 for flow in [0u64, 7, 63, 64, 16_383, 16_384, 1 << 40] {
42 let (prefix, len) = flow_prefix(flow);
43 let mut datagram = prefix[..len].to_vec();
44 datagram.extend_from_slice(b"payload");
45 assert_eq!(split_flow_datagram(&datagram), Some((flow, len)));
46 assert_eq!(&datagram[len..], b"payload");
47 }
48 }
49
50 #[test]
51 fn a_truncated_prefix_is_none() {
52 assert_eq!(split_flow_datagram(&[]), None);
53 assert_eq!(split_flow_datagram(&[0x40]), None);
54 assert_eq!(split_flow_datagram(&[0x80, 0, 0]), None);
55 }
56}