<div align="center">
# π¦ pcobs
**postcard + crc + cobs = structured data over anything**
[](https://crates.io/crates/pcobs)
[](https://docs.rs/pcobs)
[](https://www.rust-lang.org)
[](https://github.com/rust-embedded/wg)
[](https://github.com/rust-embedded/wg)
**`no_std` β’ zero-allocation β’ embedded-ready**
</div>
---
## π‘ Why?
You've got structs. You need to send them over UART/TCP/USB/whatever.
**pcobs** gives you:
- π **postcard** β compact serde serialization, `no_std` friendly
- π **CRC-16** β catch corrupted packets
- π§± **COBS framing** β zero-byte delimiters, no escaping hell
- πΎ **Zero allocations** β stack-only, no `Vec`/`Box`/`HashMap`
- β‘ **`no_std`** β works on bare-metal, no OS required
Two functions. That's it.
```rust
let len = serialize(&my_struct, &mut buf)?;
let my_struct = deserialize::<MyStruct>(&mut buf, len)?;
```
---
## π Quick Start
```toml
[dependencies]
pcobs = "1"
serde = { version = "1", features = ["derive"] }
```
```rust
use pcobs::{serialize, deserialize};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct SensorData {
id: u8,
value: f32,
flags: u16,
}
// Sender
let data = SensorData { id: 1, value: 23.5, flags: 0xABCD };
let mut buf = [0u8; 256];
let len = serialize(&data, &mut buf)?;
stream.write_all(&buf[..len])?;
stream.write_all(&[0x00])?; // COBS delimiter
// Receiver
let mut buf = [0u8; 256];
let n = read_until_delimiter(stream, &mut buf)?;
let decoded: SensorData = deserialize(&mut buf, n)?;
```
---
## π Packet Format
```
ββββββββββββββββββββββββββββββββββββββββββ¬βββββββ
β Payload β CRC-16 β 0x00 β
β postcard(your data) β checksum β β
ββββββββββββββββββββββββββββββββββββββββββ β
β COBS frame β delimβ
β no zeros in encoded data β β
ββββββββββββββββββββββββββββββββββββββββββ΄βββββββ
```
Steps:
1. Serialize your struct with **postcard**
2. Append **CRC-16** checksum (2 bytes)
3. COBS-encode the whole thing
4. Send over your transport, appending a **0x00** delimiter
---
## π Buffer Math
Encoding is done **in-place** - no buffer splitting needed. COBS adds minimal overhead (at most 1 byte per 254 bytes), plus 2 bytes for CRC.
| 64 B | ~60 B |
| 256 B | ~252 B |
| 512 B | ~508 B |
| 1024 B | ~1018 B |
---
## π οΈ Transport Agnostic
Works over anything that moves bytes:
- π‘ UART / Serial
- π TCP sockets
- π USB bulk endpoints
- π» Radio (LoRa, BLE, etc.)
- π§ͺ Pipes / files for testing
---
## β‘ Features
- **`no_std`** β works on bare-metal, no OS required
- **Zero allocations** β stack-only, no heap, embedded-friendly
- `serde` β derive your structs
- Single-pass encoding
- In-place decoding