{"id":51421894,"url":"https://github.com/firechip/cobs_codec_rs","last_synced_at":"2026-07-05T00:17:23.718Z","repository":{"id":369294835,"uuid":"1289231027","full_name":"firechip/cobs_codec_rs","owner":"firechip","description":"no_std, dependency-free Consistent Overhead Byte Stuffing (COBS) and COBS/R codec for Rust. The Rust member of the Firechip COBS family.","archived":false,"fork":false,"pushed_at":"2026-07-04T13:41:21.000Z","size":26,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T15:21:11.441Z","etag":null,"topics":["byte-stuffing","cobs","cobs-r","embedded","encoding","framing","no-std","rust","serial","uart"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/firechip.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-04T13:38:21.000Z","updated_at":"2026-07-04T13:39:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/firechip/cobs_codec_rs","commit_stats":null,"previous_names":["firechip/cobs_codec_rs"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/firechip/cobs_codec_rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/firechip","download_url":"https://codeload.github.com/firechip/cobs_codec_rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35140187,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["byte-stuffing","cobs","cobs-r","embedded","encoding","framing","no-std","rust","serial","uart"],"created_at":"2026-07-05T00:17:23.170Z","updated_at":"2026-07-05T00:17:23.688Z","avatar_url":"https://github.com/firechip.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cobs_codec_rs\n\n[![CI](https://github.com/firechip/cobs_codec_rs/actions/workflows/ci.yml/badge.svg)](https://github.com/firechip/cobs_codec_rs/actions/workflows/ci.yml)\n[![crates.io](https://img.shields.io/crates/v/cobs_codec_rs.svg)](https://crates.io/crates/cobs_codec_rs)\n[![docs.rs](https://img.shields.io/docsrs/cobs_codec_rs)](https://docs.rs/cobs_codec_rs)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n`#![no_std]`, dependency-free **Consistent Overhead Byte Stuffing (COBS)** and\n**COBS/R** for Rust — the Rust member of the Firechip COBS family (alongside the\nDart [`cobs_codec`](https://pub.dev/packages/cobs_codec) and the Kotlin\n[`cobs_codec_kt`](https://github.com/firechip/cobs_codec_kt)), verified\nbyte-identical against the shared\n[conformance vectors](https://github.com/firechip/cobs-conformance).\n\nCOBS encodes an arbitrary byte sequence into one that contains no zero (`0x00`)\nbyte, at a small and *predictable* cost: at most one extra byte per 254 bytes,\nplus one. That makes a single `0x00` a reliable packet delimiter for serial/UART,\nUSB, TCP and other byte streams — ideal for embedded and robotics protocols.\n\n## Features\n\n- **Basic COBS** and **COBS/R (Reduced)** encode/decode.\n- **`no_std` and zero dependencies** — the core `encode`/`decode` work on\n  caller-provided slices, allocating nothing.\n- **Configurable sentinel** — `*_with_sentinel` variants frame with any\n  delimiter byte, not just `0x00`.\n- **In-place decoding** — `cobs::decode_in_place` decodes without a second\n  buffer.\n- **Allocation-free streaming** — `framing::StreamDecoder` reassembles\n  delimited frames into a fixed buffer in pure `no_std`; the `alloc` feature adds\n  the owned-`Vec`\n  [`FrameDecoder`](https://docs.rs/cobs_codec_rs/latest/cobs_codec_rs/framing/struct.FrameDecoder.html)\n  and `*_to_vec` conveniences.\n- **`const fn`** size helpers (`max_encoded_len`, `encoding_overhead`) for\n  compile-time buffer sizing.\n- **Optional `serde` / `defmt`** — off by default; enable the matching feature\n  to derive `Serialize`/`Deserialize` or `defmt::Format` for `DecodeError`.\n\n## Install\n\n```toml\n[dependencies]\ncobs_codec_rs = \"1.2\"\n\n# no_std, no allocator:\n# cobs_codec_rs = { version = \"1.2\", default-features = false }\n```\n\n## Usage\n\n```rust\nuse cobs_codec_rs::{cobs, cobsr};\n\n// With alloc (default):\nlet encoded = cobs::encode_to_vec(\u0026[0x11, 0x22, 0x00, 0x33]);\nassert_eq!(encoded, [0x03, 0x11, 0x22, 0x02, 0x33]); // no 0x00\nassert_eq!(cobs::decode_to_vec(\u0026encoded).unwrap(), [0x11, 0x22, 0x00, 0x33]);\n\n// COBS/R often saves the trailing overhead byte:\nassert_eq!(cobsr::encode_to_vec(b\"12345\"), b\"51234\"); // same length as input\n```\n\n`no_std`, into a fixed buffer:\n\n```rust\nuse cobs_codec_rs::{cobs, max_encoded_len};\n\nlet src = [0x11, 0x00, 0x22];\nlet mut buf = [0u8; max_encoded_len(3)];\nlet n = cobs::encode(\u0026src, \u0026mut buf);\nassert_eq!(\u0026buf[..n], \u0026[0x02, 0x11, 0x02, 0x22]);\n```\n\nWith a custom sentinel byte, so a non-`0x00` byte delimits frames (both `cobs`\nand `cobsr`, slice and `*_to_vec` variants):\n\n```rust\nuse cobs_codec_rs::cobs;\n\n// 0xAA delimits frames instead of 0x00; the encoded output never contains it.\n// (`sentinel == 0` is identical to the plain codec.)\nlet encoded = cobs::encode_to_vec_with_sentinel(\u0026[0x11, 0xAA, 0x22], 0xAA);\nassert_eq!(encoded, [0xAE, 0xBB, 0x00, 0x88]); // no 0xAA byte\nassert_eq!(\n    cobs::decode_to_vec_with_sentinel(\u0026encoded, 0xAA).unwrap(),\n    [0x11, 0xAA, 0x22],\n);\n```\n\nDecoding in place, without a second buffer (basic COBS only):\n\n```rust\nuse cobs_codec_rs::cobs;\n\n// COBS never expands on decode, so it can decode within the input buffer; the\n// decoded bytes end up in `buf[..len]`.\nlet mut buf = [0x03, 0x11, 0x22, 0x02, 0x33];\nlet len = cobs::decode_in_place(\u0026mut buf).unwrap();\nassert_eq!(\u0026buf[..len], \u0026[0x11, 0x22, 0x00, 0x33]);\n```\n\nReassembling a sentinel-delimited stream with no allocator, into a fixed buffer:\n\n```rust\nuse cobs_codec_rs::cobs;\nuse cobs_codec_rs::framing::StreamDecoder;\n\n// Encode a packet with sentinel 0xAA, then delimit it with an 0xAA byte.\nlet mut wire = [0u8; 16];\nlet n = cobs::encode_with_sentinel(\u0026[0x11, 0x00, 0x22], \u0026mut wire, 0xAA);\nwire[n] = 0xAA;\n\n// Reassemble it into a fixed scratch buffer — no allocation anywhere.\nlet mut scratch = [0u8; 8];\nlet mut decoder = StreamDecoder::new(\u0026mut scratch).sentinel(0xAA); // .reduced(true) for COBS/R\n\nlet mut out = [0u8; 8];\nlet mut out_len = 0;\ndecoder.push(\u0026wire[..n + 1], |frame| {\n    let frame = frame.unwrap();\n    out[..frame.len()].copy_from_slice(frame);\n    out_len = frame.len();\n});\nassert_eq!(\u0026out[..out_len], \u0026[0x11, 0x00, 0x22]);\n```\n\nReading a delimited serial stream (needs `alloc`):\n\n```rust\nuse cobs_codec_rs::framing::{frame_to_vec, FrameDecoder};\n\nlet mut rx = FrameDecoder::new().max_frame_len(4096);\n// `chunk` is any \u0026[u8] read from the link; chunks need not align with frames.\n# let chunk = frame_to_vec(\u0026[0x01, 0x02]);\nrx.push(\u0026chunk, |frame| match frame {\n    Ok(packet) =\u003e { /* handle packet */ }\n    Err(err)   =\u003e { /* corrupt frame; keep receiving */ let _ = err; }\n});\n```\n\n### Framing Protocol Buffers over serial\n\nCOBS is the standard way to frame **Protobuf** on a UART/RS-485 link: protobuf\nserializes a message but doesn't delimit it, and COBS supplies the missing\n`0x00`-delimited framing — with instant resync after line noise, unlike\nlength-prefixing. See [`examples/protobuf_cobs.rs`](examples/protobuf_cobs.rs)\nfor a runnable device→host demo (`cargo run --example protobuf_cobs`) that\nsurvives a corrupted frame.\n\n## Overhead\n\nCOBS overhead is *data-independent*. Encoding an `n`-byte packet produces at most\n\n$$ n + \\left\\lceil \\frac{n}{254} \\right\\rceil $$\n\nbytes (one extra byte per 254, rounded up), so the overhead is bounded by\n$\\left\\lceil n/254 \\right\\rceil$ and is always at least one byte. By contrast,\nescape-based schemes (PPP, SLIP, HDLC) can *double* the packet in the worst case.\n`cobsr` (COBS/R) can reach zero overhead. These bounds are what `max_encoded_len`\nand `encoding_overhead` return.\n\n## Benchmarks\n\nThroughput on a 1 KiB payload (`cargo bench`, criterion), on an AMD Ryzen 7\n3800XT under WSL2 — indicative, not a controlled benchmark:\n\n| Operation | Throughput |\n| --------- | ---------- |\n| COBS encode | ~835 MiB/s |\n| COBS decode | ~1.40 GiB/s |\n| COBS/R encode | ~832 MiB/s |\n\n## Integrations\n\nThe core stays `no_std` and dependency-free, so framework glue lives in your\nproject rather than in the crate. [INTEGRATIONS.md](INTEGRATIONS.md) has verified\ncopy-paste recipes — a `tokio_util::codec` for `Framed` streams, and the\n`embedded-io` shape for `no_std` targets — all built on the public API.\n\n## Background\n\nStuart Cheshire and Mary Baker, \"Consistent Overhead Byte Stuffing\",\n*IEEE/ACM Transactions on Networking*, Vol. 7, No. 2, April 1999. **COBS/R** is a\nvariant by Craig McQueen.\n\n## License\n\nMIT © 2026 Alexander Salas Bastidas ([Firechip](https://firechip.dev)). See\n[LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirechip%2Fcobs_codec_rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffirechip%2Fcobs_codec_rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirechip%2Fcobs_codec_rs/lists"}