indexbus_msg/
lib.rs

1#![cfg_attr(not(any(feature = "std", test)), no_std)]
2#![deny(unreachable_pub, rust_2018_idioms)]
3#![deny(missing_docs)]
4
5//! Structured message envelope for IndexBus.
6//!
7//! This crate defines a small, versioned, bytes-on-wire header designed to live at the start of
8//! `Slot.data[..]`.
9//!
10//! ## Contracts and invariants
11//!
12//! - The v1 envelope is little-endian and begins with [`MAGIC`].
13//! - The header is designed to be append-only over time. [`decode_header`] accepts
14//!   `header_len >= V1_HEADER_LEN` and ignores any appended bytes it does not understand.
15//! - [`encode_header_into`] currently only emits the minimum v1 header (`header_len == V1_HEADER_LEN`).
16//! - `header_len + payload_len` is validated to be within [`SLOT_CAPACITY`].
17//!
18//! This crate intentionally does not interpret payload bytes. Fields such as `codec_id`,
19//! `schema_id`, and `msg_type` are treated as application-defined identifiers.
20//!
21//! ## Error semantics
22//!
23//! - Decode helpers validate structural properties (magic, lengths, known flags).
24//! - Decode helpers do not attempt to authenticate the payload or validate codec-specific formats.
25//! - `flags` are treated as declarative metadata; the helpers reject unknown bits for deterministic
26//!   behavior.
27//!
28//! ## Features
29//!
30//! - Default: `no_std`.
31//! - `alloc`: reserved for future heap-backed conveniences.
32//! - `std`: enables `std`-only trait impls (e.g. `std::error::Error`) and implies `alloc`.
33//!
34//! ## Minimal v1 encode/decode
35//!
36//! ```
37//! use indexbus_msg::{decode_header, encode_header_into, Header, V1_HEADER_LEN};
38//!
39//! let payload = b"hello";
40//! let hdr = Header {
41//!     flags: 0,
42//!     codec_id: 0,
43//!     header_len: V1_HEADER_LEN as u8,
44//!     schema_id: 1,
45//!     msg_type: 42,
46//!     msg_version: 1,
47//!     payload_len: payload.len() as u16,
48//! };
49//!
50//! let mut buf = [0u8; 64];
51//! let n = encode_header_into(&mut buf, hdr).unwrap();
52//! buf[n..(n + payload.len())].copy_from_slice(payload);
53//!
54//! let (parsed, parsed_payload) = decode_header(&buf[..(n + payload.len())]).unwrap();
55//! assert_eq!(parsed, hdr);
56//! assert_eq!(parsed_payload, payload);
57//! ```
58
59#[cfg(feature = "std")]
60extern crate std;
61
62mod constants;
63mod errors;
64mod header;
65mod utils;
66
67mod internal;
68
69pub use constants::*;
70pub use errors::Error;
71pub use header::{decode_header, encode_header_into, Header};
72
73/// Curated prelude for downstream users.
74pub mod prelude {
75    pub use crate::{decode_header, encode_header_into, Error, Header};
76    pub use crate::{flags, MAGIC, V1_HEADER_LEN};
77}
78
79pub mod flags {
80    //! Envelope flag definitions.
81    //!
82    //! Flag bits stored in [`crate::Header::flags`].
83
84    /// Indicates that an additional CRC field may be present.
85    ///
86    /// This crate does not compute or verify a CRC; the bit is reserved for higher-level
87    /// adapters/protocols.
88    pub const CRC32_PRESENT: u16 = 1 << 0;
89    /// Indicates that the payload bytes are compressed (codec-specific).
90    pub const COMPRESSED: u16 = 1 << 1;
91    /// Indicates that the payload bytes are signed/authenticated (platform-specific).
92    pub const SIGNED: u16 = 1 << 2;
93}
94
95#[cfg(test)]
96mod header_tests;