Skip to main content

streaming_crypto/core_api/stream_v2/framing/
decode.rs

1use crate::stream_v2::framing::types::FrameView;
2use crate::stream_v2::framing::types::{FrameHeader, FrameError};
3
4// ✅ **This is framing-only**
5// ✅ **No duplicate decode logic**
6// ✅ **Zero-copy slicing works perfectly**
7#[inline]
8pub fn decode_frame_header(buf: &[u8]) -> Result<FrameHeader, FrameError> {
9    FrameHeader::from_bytes(buf)
10}
11
12/// Decode a single frame from bytes.
13///
14/// Caller guarantees:
15/// - Full frame bytes are provided
16/// - Ordering is handled externally
17pub fn decode_frame(wire: &[u8]) -> Result<FrameView<'_>, FrameError> {
18    let header = FrameHeader::from_bytes(wire)?;
19
20    let expected_len = FrameHeader::LEN + header.ciphertext_len() as usize;
21    if wire.len() != expected_len {
22        return Err(FrameError::LengthMismatch {
23            expected: expected_len,
24            actual: wire.len(),
25        });
26    }
27
28    let ciphertext = &wire[FrameHeader::LEN..expected_len];
29
30    Ok(FrameView { header, ciphertext })
31
32    // 🚫 no `Vec`
33    // 🚫 no allocation
34    // 🚫 no copy
35    // ✔ constant time
36    // ✔ cache-friendly
37}
38
39// ### In‑Place Decode
40
41#[inline]
42pub fn decode_header_in_place(buf: &[u8]) -> Result<FrameHeader, FrameError> {
43    FrameHeader::from_bytes(buf)
44}
45
46pub fn decode_in_place<'a>(wire: &'a [u8]) -> Result<FrameView<'a>, FrameError> {
47    let header = FrameHeader::from_bytes(wire)?;
48
49    let expected_len = FrameHeader::LEN + header.ciphertext_len() as usize;
50    if wire.len() != expected_len {
51        return Err(FrameError::LengthMismatch {
52            expected: expected_len,
53            actual: wire.len(),
54        });
55    }
56
57    let ciphertext = &wire[FrameHeader::LEN..expected_len];
58
59    Ok(FrameView { header, ciphertext })
60}
61
62// ### Key Differences
63// - **Caller provides buffer**: `encode_frame_in_place` writes directly into a `BytesMut` supplied by the caller, instead of returning a new `Vec<u8>`.
64// - **No extra allocations**: We control buffer reuse (e.g., via a slab allocator), so repeated calls don’t churn the allocator.
65// - **Decode stays zero‑copy**: It just slices into the provided wire buffer, no new allocations.
66
67// ### Usage Example
68// ```rust
69// let mut buf = BytesMut::with_capacity(FrameHeader::LEN + ciphertext.len());
70// encode_frame_in_place(&header, &ciphertext, &mut buf)?;
71// let wire = buf.freeze();
72
73// let view = decode_frame_in_place(&wire)?;
74// ```