Rust library for reading and writing Capsule container files (see the repository’s SPEC.md).
Capsule is a framing/container format:
- It provides a fixed-width ASCII prelude + header block + payload block.
- The payload is always treated as an opaque byte blob at the Capsule layer.
- Encoding selection (A/B/C) defines how header/payload bytes are represented in the container.
This library is intentionally strict/deterministic:
- Header length is measured in encoded bytes as stored.
- CRC-32 verification is supported (enabled by default when parsing).
- ASCII header
key=value\nparsing is provided when Encoding = A.
If you vendor this repo into a larger workspace:
[dependencies]
capsule-lib = { path = "path/to/capsule/crates/capsule-lib" }If you depend on a git checkout (fill in the URL + revision you want):
[dependencies]
capsule-lib = { git = "<REPO_URL>", rev = "<GIT_SHA>", package = "capsule-lib" }Capsule::parse(...)/Capsule::parse_with_options(...)parse a full Capsule file from bytes.Capsule::to_bytes()serializes aCapsuleback to bytes (recomputes CRC).Capsule::from_decoded(...)builds a Capsule from decoded header/payload inputs.CapsuleDecodedis the parse result (prelude + encoded + decoded bytes).ParseOptionscontrols CRC verification and encoding validation.
use std::fs;
use capsule_lib::{Capsule, ParseOptions, Encoding};
fn main() -> capsule_lib::CapsuleResult<()> {
let bytes = fs::read("input.capsule").unwrap();
// Strict mode (recommended for verification tooling).
let decoded = Capsule::parse_with_options(
&bytes,
ParseOptions { verify_crc: true, validate_encoding: true },
)?;
match decoded.prelude.encoding {
Encoding::Ascii => {
// For Encoding=A: header_fields is populated and payload_decoded is ASCII bytes.
if let Some(fields) = decoded.header_fields {
for f in fields {
println!("{}={}", f.key, f.value);
}
}
// Payload is still opaque at the Capsule layer.
let payload: &[u8] = &decoded.payload_decoded;
println!("payload len: {}", payload.len());
}
Encoding::Base64 => {
// For Encoding=B: payload_decoded is Base64-decoded bytes.
let payload: &[u8] = &decoded.payload_decoded;
println!("decoded payload len: {}", payload.len());
}
Encoding::Cbor => {
// For Encoding=C: this library does not interpret CBOR. When validation is enabled,
// it validates well-formedness only (accepts a CBOR sequence).
let payload: &[u8] = &decoded.payload_decoded;
println!("cbor payload bytes: {}", payload.len());
}
}
Ok(())
}use capsule_lib::ascii_header::HeaderField;
use capsule_lib::{Capsule, Encoding, Version};
fn main() -> capsule_lib::CapsuleResult<()> {
let header_fields = vec![
HeaderField { key: "dialect".to_string(), value: "example/1".to_string() },
HeaderField { key: "id".to_string(), value: "123".to_string() },
];
let payload = b"hello\n";
let capsule = Capsule::from_decoded(
Version(0x0001),
Encoding::Ascii,
Some(&header_fields),
&[],
payload,
)?;
let bytes = capsule.to_bytes()?;
std::fs::write("out.capsule", bytes).unwrap();
Ok(())
}verify_crc=trueis recommended forcapsule verify-style behavior.validate_encoding=trueperforms lexical validation only:- A: rejects non-ASCII bytes in header/payload
- B: strict RFC 4648 Base64 decode
- C: validates CBOR well-formedness and accepts a CBOR sequence (0..N items)
- The Capsule container format version emitted by tooling is currently
0001. capsule-libtreats payload bytes as opaque; higher-level parsers can interpret payload content as needed.