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}