cobs_codec_rs 1.2.0

Consistent Overhead Byte Stuffing (COBS) and COBS/R codec: no_std, zero-dependency, for zero-free framing of serial and packet byte streams.
Documentation
  • Coverage
  • 100%
    52 out of 52 items documented5 out of 39 items with examples
  • Size
  • Source code size: 74.82 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 632.83 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 2s Average build duration of successful builds.
  • all releases: 4s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • firechip/cobs_codec_rs
    1 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • ajsb85 github:firechip:packages

cobs_codec_rs

CI crates.io docs.rs License: MIT

#![no_std], dependency-free Consistent Overhead Byte Stuffing (COBS) and COBS/R for Rust — the Rust member of the Firechip COBS family (alongside the Dart cobs_codec and the Kotlin cobs_codec_kt), verified byte-identical against the shared conformance vectors.

COBS encodes an arbitrary byte sequence into one that contains no zero (0x00) byte, at a small and predictable cost: at most one extra byte per 254 bytes, plus one. That makes a single 0x00 a reliable packet delimiter for serial/UART, USB, TCP and other byte streams — ideal for embedded and robotics protocols.

Features

  • Basic COBS and COBS/R (Reduced) encode/decode.
  • no_std and zero dependencies — the core encode/decode work on caller-provided slices, allocating nothing.
  • Configurable sentinel*_with_sentinel variants frame with any delimiter byte, not just 0x00.
  • In-place decodingcobs::decode_in_place decodes without a second buffer.
  • Allocation-free streamingframing::StreamDecoder reassembles delimited frames into a fixed buffer in pure no_std; the alloc feature adds the owned-Vec FrameDecoder and *_to_vec conveniences.
  • const fn size helpers (max_encoded_len, encoding_overhead) for compile-time buffer sizing.

Install

[dependencies]
cobs_codec_rs = "1.2"

# no_std, no allocator:
# cobs_codec_rs = { version = "1.2", default-features = false }

Usage

use cobs_codec_rs::{cobs, cobsr};

// With alloc (default):
let encoded = cobs::encode_to_vec(&[0x11, 0x22, 0x00, 0x33]);
assert_eq!(encoded, [0x03, 0x11, 0x22, 0x02, 0x33]); // no 0x00
assert_eq!(cobs::decode_to_vec(&encoded).unwrap(), [0x11, 0x22, 0x00, 0x33]);

// COBS/R often saves the trailing overhead byte:
assert_eq!(cobsr::encode_to_vec(b"12345"), b"51234"); // same length as input

no_std, into a fixed buffer:

use cobs_codec_rs::{cobs, max_encoded_len};

let src = [0x11, 0x00, 0x22];
let mut buf = [0u8; max_encoded_len(3)];
let n = cobs::encode(&src, &mut buf);
assert_eq!(&buf[..n], &[0x02, 0x11, 0x02, 0x22]);

Reading a delimited serial stream (needs alloc):

use cobs_codec_rs::framing::{frame_to_vec, FrameDecoder};

let mut rx = FrameDecoder::new().max_frame_len(4096);
// `chunk` is any &[u8] read from the link; chunks need not align with frames.
# let chunk = frame_to_vec(&[0x01, 0x02]);
rx.push(&chunk, |frame| match frame {
    Ok(packet) => { /* handle packet */ }
    Err(err)   => { /* corrupt frame; keep receiving */ let _ = err; }
});

Overhead

COBS overhead is data-independent. Encoding an n-byte packet produces at most

$$ n + \left\lceil \frac{n}{254} \right\rceil $$

bytes (one extra byte per 254, rounded up), so the overhead is bounded by $\left\lceil n/254 \right\rceil$ and is always at least one byte. By contrast, escape-based schemes (PPP, SLIP, HDLC) can double the packet in the worst case. cobsr (COBS/R) can reach zero overhead. These bounds are what max_encoded_len and encoding_overhead return.

Background

Stuart Cheshire and Mary Baker, "Consistent Overhead Byte Stuffing", IEEE/ACM Transactions on Networking, Vol. 7, No. 2, April 1999. COBS/R is a variant by Craig McQueen.

License

MIT © 2026 Alexander Salas Bastidas (Firechip). See LICENSE.