Skip to content

Commit f7951f4

Browse files
committed
docs: document configurable sentinel, in-place decode, sentinel framing
Explain the 1.1.0 features with usage examples in the README.
1 parent 2ea7597 commit f7951f4

1 file changed

Lines changed: 62 additions & 2 deletions

File tree

README.md

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ schemes such as PPP byte stuffing, COBS never doubles a packet's size.
2525
- 🔌 **Stream framing built in** — turn a raw serial byte stream into a stream of
2626
decoded packets with `CobsFrameDecoder`; chunk boundaries don't have to align
2727
with frames.
28+
- 🚩 **Configurable delimiter (sentinel)** — encode and decode COBS *and* COBS/R
29+
so the output avoids any chosen byte, not just `0x00`, letting that byte delimit
30+
frames instead.
31+
- 🏷️ **Sentinel-aware framing** — the framing helpers and the stream decoder can
32+
split on the chosen `sentinel` rather than `0x00`.
33+
- ♻️ **In-place decode** — decode basic COBS inside the same buffer with no second
34+
allocation; COBS never expands on decode.
2835
- 🎯 **Zero dependencies, all platforms** — pure Dart (`dart:typed_data`), works
2936
on mobile, desktop, web, server and CLI. Uses `Uint8List` throughout.
3037
- 📏 **Predictable sizing**`maxEncodedLength` / `encodingOverhead` for buffer
@@ -109,6 +116,56 @@ outgoingPackets
109116
.listen(serialPort.add);
110117
```
111118

119+
### A custom delimiter byte (sentinel)
120+
121+
Need a delimiter other than `0x00` — say a byte your protocol reserves for
122+
framing? The `…WithSentinel` variants make the encoding avoid an arbitrary
123+
`sentinel` byte instead (they XOR the finished encoding with it), so that byte can
124+
delimit frames:
125+
126+
```dart
127+
final data = [0x11, 0x22, 0x00, 0x33];
128+
129+
final encoded = cobsEncodeWithSentinel(data, 0xAA); // [0xA9, 0xBB, 0x88, 0xA8, 0x99] — no 0xAA
130+
final decoded = cobsDecodeWithSentinel(encoded, 0xAA); // [0x11, 0x22, 0x00, 0x33]
131+
132+
// COBS/R has the same pair.
133+
cobsrEncodeWithSentinel(data, 0xAA); // [0xA9, 0xBB, 0x88, 0x99]
134+
```
135+
136+
`sentinel == 0` is byte-for-byte identical to the plain codec, and decoding never
137+
mutates its input.
138+
139+
### Decoding in place
140+
141+
Basic COBS never expands on decode, so it can be decoded within the same buffer —
142+
no second allocation. `cobsDecodeInPlace` overwrites the buffer with the decoded
143+
bytes and returns their length:
144+
145+
```dart
146+
final buffer = Uint8List.fromList(cobs.encode([0x11, 0x22, 0x00, 0x33]));
147+
// buffer == [0x03, 0x11, 0x22, 0x02, 0x33]
148+
149+
final n = cobsDecodeInPlace(buffer); // 4
150+
final decoded = Uint8List.sublistView(buffer, 0, n); // [0x11, 0x22, 0x00, 0x33]
151+
```
152+
153+
`cobsDecodeInPlaceWithSentinel(buffer, sentinel)` does the same for a custom
154+
delimiter. (COBS/R can expand on decode, so it has no in-place form.)
155+
156+
### Framing on a custom sentinel
157+
158+
`cobsFrame` / `cobsUnframe` and both stream transformers take the same optional
159+
`sentinel`, so a whole link can be delimited by a byte other than `0x00`:
160+
161+
```dart
162+
final frame = cobsFrame([0x11, 0x00, 0x22], sentinel: 0xAA); // [0xA8, 0xBB, 0xA8, 0x88, 0xAA]
163+
final packets = cobsUnframe(frame, sentinel: 0xAA); // [[0x11, 0x00, 0x22]]
164+
165+
// The stream decoder frames on the same byte:
166+
serialPort.transform(const CobsFrameDecoder(sentinel: 0xAA));
167+
```
168+
112169
### Composing with other codecs
113170

114171
Because they are `Codec`s, you can `fuse` COBS with anything:
@@ -148,10 +205,13 @@ same. Compare PPP/SLIP escape stuffing, whose worst case **doubles** the packet.
148205
| `cobs` / `cobsr` | Shared `Codec` instances (basic COBS and COBS/R). |
149206
| `cobsEncode` / `cobsDecode` | Direct basic-COBS functions. |
150207
| `cobsrEncode` / `cobsrDecode` | Direct COBS/R functions. |
208+
| `cobsEncodeWithSentinel` / `cobsDecodeWithSentinel` | Basic COBS against an arbitrary delimiter byte. |
209+
| `cobsrEncodeWithSentinel` / `cobsrDecodeWithSentinel` | COBS/R against an arbitrary delimiter byte. |
210+
| `cobsDecodeInPlace` / `cobsDecodeInPlaceWithSentinel` | Decode basic COBS within the buffer; returns the length. |
151211
| `CobsCodec`, `CobsEncoder`, `CobsDecoder` | `dart:convert` classes for basic COBS. |
152212
| `CobsrCodec`, `CobsrEncoder`, `CobsrDecoder` | `dart:convert` classes for COBS/R. |
153-
| `cobsFrame` / `cobsUnframe` | Add / split the `0x00` frame delimiter. |
154-
| `CobsFrameEncoder` / `CobsFrameDecoder` | Stream transformers for framed links. |
213+
| `cobsFrame` / `cobsUnframe` | Add / split the frame delimiter (`0x00` or a custom `sentinel`). |
214+
| `CobsFrameEncoder` / `CobsFrameDecoder` | Stream transformers for framed links (optional `sentinel`). |
155215
| `cobsDelimiter` | The frame delimiter byte (`0x00`). |
156216
| `encodingOverhead` / `maxEncodedLength` | Size bounds. |
157217
| `cobsMaxBlockLength` | Max data bytes per COBS block (`254`). |

0 commit comments

Comments
 (0)