Skip to main content

BcpDecoder

Struct BcpDecoder 

Source
pub struct BcpDecoder;
Expand description

Synchronous BCP decoder — parses a complete in-memory payload.

The decoder reads an entire BCP payload from a byte slice and produces a DecodedPayload containing the header and all typed blocks. It is the inverse of BcpEncoder::encode from the bcp-encoder crate.

Decoding proceeds in four steps:

  1. Header: Validate and parse the 8-byte file header (magic number, version, flags, reserved byte).
  2. Whole-payload decompression: If the header’s COMPRESSED flag (bit 0) is set, decompress all bytes after the header with zstd before parsing block frames.
  3. Block frames: Iterate block frames by reading BlockFrame envelopes. For each frame:
    • If COMPRESSED (bit 1): decompress the body with zstd.
    • If IS_REFERENCE (bit 2): resolve the 32-byte BLAKE3 hash against the content store to recover the original body.
    • Extract the summary sub-block if HAS_SUMMARY (bit 0) is set.
    • Deserialize the body into the corresponding BlockContent.
  4. Termination: Stop when an END sentinel (type=0xFF) is encountered. Detect and report trailing data after the sentinel.

Unknown block types are captured as BlockContent::Unknown and do not cause errors — this is the forward compatibility guarantee from RFC §3, P1 Schema Evolution.

§Example

use bcp_encoder::BcpEncoder;
use bcp_decoder::BcpDecoder;
use bcp_types::enums::{Lang, Role};

let payload = BcpEncoder::new()
    .add_code(Lang::Rust, "main.rs", b"fn main() {}")
    .add_conversation(Role::User, b"hello")
    .encode()
    .unwrap();

let decoded = BcpDecoder::decode(&payload).unwrap();
assert_eq!(decoded.blocks.len(), 2);

Implementations§

Source§

impl BcpDecoder

Source

pub fn decode(payload: &[u8]) -> Result<DecodedPayload, DecodeError>

Decode a complete BCP payload from a byte slice.

This is the standard entry point for payloads that do not contain content-addressed (reference) blocks. If the payload contains blocks with the IS_REFERENCE flag, use decode_with_store instead.

Handles whole-payload and per-block zstd decompression transparently.

§Errors
Source

pub fn decode_with_store( payload: &[u8], store: &dyn ContentStore, ) -> Result<DecodedPayload, DecodeError>

Decode a payload that may contain content-addressed blocks.

Same as decode, but accepts a ContentStore for resolving IS_REFERENCE blocks. When a block’s body is a 32-byte BLAKE3 hash, the decoder looks it up in the store to retrieve the original body bytes.

§Errors

All errors from decode, plus:

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.