Skip to main content

bcp_types/
end.rs

1use crate::error::TypeError;
2
3/// END sentinel — marks the end of the block stream.
4///
5/// The END block has no fields and no body. Its presence on the wire is
6/// signaled solely by the block type byte (0xFF) in the block frame
7/// header. The `bcp_wire::BlockFrame::read_from` method returns `None`
8/// when it encounters an END block, terminating the read loop.
9///
10/// Unlike other block types that carry TLV-encoded fields, `EndBlock`
11/// is a zero-field struct. Its `encode_body` always returns an empty
12/// vec and its `decode_body` succeeds only on empty input.
13///
14/// Wire layout:
15///
16/// ```text
17/// ┌──────────────────────────────────────┐
18/// │ block_type = 0xFF (varint, 2 bytes)  │
19/// │ (no flags, no content_len, no body)  │
20/// └──────────────────────────────────────┘
21/// ```
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct EndBlock;
24
25impl EndBlock {
26    /// Serialize the END block body — always empty.
27    pub fn encode_body(&self) -> Vec<u8> {
28        Vec::new()
29    }
30
31    /// Deserialize an END block from a body buffer.
32    ///
33    /// Succeeds on empty input. Non-empty input is accepted but ignored,
34    /// since a future spec revision could attach trailing metadata to
35    /// the END sentinel.
36    pub fn decode_body(_buf: &[u8]) -> Result<Self, TypeError> {
37        Ok(Self)
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn encode_produces_empty_body() {
47        let block = EndBlock;
48        assert!(block.encode_body().is_empty());
49    }
50
51    #[test]
52    fn decode_empty_body() {
53        let block = EndBlock::decode_body(&[]).unwrap();
54        assert_eq!(block, EndBlock);
55    }
56
57    #[test]
58    fn decode_ignores_trailing_bytes() {
59        let block = EndBlock::decode_body(&[0xFF, 0x00]).unwrap();
60        assert_eq!(block, EndBlock);
61    }
62}