Skip to content

Commit d555943

Browse files
committed
build: adopt edition 2024, bump msrv to 1.85, add docs.rs math
No API changes; merged #2 (checkout v7) and closed #1 (bad MSRV bump).
1 parent db2f692 commit d555943

12 files changed

Lines changed: 112 additions & 21 deletions

File tree

.github/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ updates:
2222
- "github-actions"
2323
commit-message:
2424
prefix: "ci"
25+
ignore:
26+
# The msrv job pins dtolnay/rust-toolchain to the crate's declared MSRV on
27+
# purpose; raise it only when bumping rust-version, never automatically.
28+
- dependency-name: "dtolnay/rust-toolchain"

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ jobs:
5151
run: cargo build --no-default-features --target thumbv7em-none-eabihf
5252

5353
msrv:
54-
name: minimum supported Rust (1.81)
54+
name: minimum supported Rust (1.85)
5555
runs-on: ubuntu-latest
5656
steps:
5757
- uses: actions/checkout@v7
58-
- uses: dtolnay/rust-toolchain@1.81.0
58+
- uses: dtolnay/rust-toolchain@1.85.0
5959
- run: cargo build --all-features
6060

6161
conformance:

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@
33
All notable changes to this crate are documented here. This project adheres to
44
[Semantic Versioning](https://semver.org).
55

6+
## 1.2.0
7+
8+
### Changed
9+
10+
- Adopted **Rust edition 2024**; the minimum supported Rust version is now
11+
**1.85** (required by the edition). No API changes.
12+
- Modernised CI: bumped `actions/checkout` to v7 and pinned the MSRV job's
13+
toolchain to Rust 1.85.
14+
15+
### Documentation
16+
17+
- The Cheshire & Baker (1999) overhead bounds now render as math on docs.rs (via
18+
KaTeX): the encoded length is at most $n + \lceil n/254 \rceil$ bytes, and
19+
`max_encoded_len` / `encoding_overhead` document their closed forms.
20+
621
## 1.1.0
722

823
### Added

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "cobs_codec_rs"
3-
version = "1.1.0"
4-
edition = "2021"
5-
rust-version = "1.81"
3+
version = "1.2.0"
4+
edition = "2024"
5+
rust-version = "1.85"
66
description = "Consistent Overhead Byte Stuffing (COBS) and COBS/R codec: no_std, zero-dependency, for zero-free framing of serial and packet byte streams."
77
authors = ["Alexander Salas Bastidas <ajsb85@firechip.dev>"]
88
license = "MIT"
@@ -13,6 +13,12 @@ readme = "README.md"
1313
keywords = ["cobs", "serial", "framing", "no-std", "embedded"]
1414
categories = ["encoding", "embedded", "no-std"]
1515

16+
[package.metadata.docs.rs]
17+
# Document every feature, and load KaTeX so the overhead math renders. KaTeX is
18+
# documentation-support JavaScript, which docs.rs permits; it does no tracking.
19+
all-features = true
20+
rustdoc-args = ["--html-in-header", "docs/katex-header.html"]
21+
1622
[features]
1723
default = ["std"]
1824
# Enables the `*_to_vec` convenience functions and framing that allocate.

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ USB, TCP and other byte streams — ideal for embedded and robotics protocols.
3838

3939
```toml
4040
[dependencies]
41-
cobs_codec_rs = "1.1"
41+
cobs_codec_rs = "1.2"
4242

4343
# no_std, no allocator:
44-
# cobs_codec_rs = { version = "1.1", default-features = false }
44+
# cobs_codec_rs = { version = "1.2", default-features = false }
4545
```
4646

4747
## Usage
@@ -85,9 +85,15 @@ rx.push(&chunk, |frame| match frame {
8585

8686
## Overhead
8787

88-
COBS overhead is data-independent: at most `⌈n / 254⌉` extra bytes for `n` input
89-
bytes (and always ≥ 1). Compare escape-based schemes (PPP/SLIP), whose worst case
90-
*doubles* the packet.
88+
COBS overhead is *data-independent*. Encoding an `n`-byte packet produces at most
89+
90+
$$ n + \left\lceil \frac{n}{254} \right\rceil $$
91+
92+
bytes (one extra byte per 254, rounded up), so the overhead is bounded by
93+
$\left\lceil n/254 \right\rceil$ and is always at least one byte. By contrast,
94+
escape-based schemes (PPP, SLIP, HDLC) can *double* the packet in the worst case.
95+
`cobsr` (COBS/R) can reach zero overhead. These bounds are what `max_encoded_len`
96+
and `encoding_overhead` return.
9197

9298
## Background
9399

docs/katex-header.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!-- KaTeX math rendering for docs.rs. Renders $…$ / $$…$$ in the docs client-side.
2+
This is documentation-support JavaScript (KaTeX), which docs.rs permits; it
3+
does no tracking. See https://docs.rs/about/metadata -->
4+
<link
5+
rel="stylesheet"
6+
href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.11/katex.min.css"
7+
crossorigin="anonymous"
8+
/>
9+
<script
10+
defer
11+
src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.11/katex.min.js"
12+
crossorigin="anonymous"
13+
></script>
14+
<script
15+
defer
16+
src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.11/contrib/auto-render.min.js"
17+
crossorigin="anonymous"
18+
></script>
19+
<script>
20+
document.addEventListener("DOMContentLoaded", function () {
21+
renderMathInElement(document.body, {
22+
delimiters: [
23+
{ left: "$$", right: "$$", display: true },
24+
{ left: "\\[", right: "\\]", display: true },
25+
{ left: "$", right: "$", display: false },
26+
{ left: "\\(", right: "\\)", display: false },
27+
],
28+
throwOnError: false,
29+
});
30+
});
31+
</script>

src/framing.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! allocating (usable in pure `no_std`); [`FrameDecoder`] (behind the `alloc`
88
//! feature) does the same into owned [`Vec`]s.
99
10-
use crate::{cobs, DecodeError, DELIMITER};
10+
use crate::{DELIMITER, DecodeError, cobs};
1111

1212
#[cfg(feature = "alloc")]
1313
use crate::cobsr;

src/lib.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,31 @@
3737
//! assert_eq!(&buf[..n], &[0x02, 0x11, 0x02, 0x22]);
3838
//! ```
3939
//!
40+
//! # Encoding overhead
41+
//!
42+
//! COBS has a *tight, data-independent* bound on overhead. Encoding an $n$-byte
43+
//! packet yields at most
44+
//!
45+
//! $$ n + \left\lceil \frac{n}{254} \right\rceil $$
46+
//!
47+
//! bytes (one extra byte per 254, rounded up), so the overhead $o(n)$ obeys
48+
//!
49+
//! $$ 1 \le o(n) \le \left\lceil \frac{n}{254} \right\rceil \quad (n \ge 1) $$
50+
//!
51+
//! and [`max_encoded_len`] and [`encoding_overhead`] return exactly these
52+
//! worst-case bounds. By contrast, escape-based framing (PPP, SLIP, HDLC) can
53+
//! *double* a packet in the worst case, an overhead of up to $n$ bytes, because
54+
//! any byte may need escaping.
55+
//!
56+
//! The bound follows from the block structure: COBS emits *blocks*, each a
57+
//! *code byte* $c$ followed by $c - 1$ non-zero data bytes. A code $c \lt 255$
58+
//! stands for those bytes then an implicit zero; $c = 255$ carries a full run of
59+
//! $254$ non-zero bytes (see [`MAX_BLOCK_LEN`]) with no trailing zero. At most
60+
//! one code byte is spent per 254 data bytes, so an $n$-byte packet needs at
61+
//! most $\left\lceil \frac{n}{254} \right\rceil$ of them. [`cobsr`] (COBS/R)
62+
//! drops the final code byte when the last data byte can stand in for it,
63+
//! reaching a best case of *zero* overhead.
64+
//!
4065
//! See "Consistent Overhead Byte Stuffing" by Stuart Cheshire and Mary Baker,
4166
//! IEEE/ACM Transactions on Networking, Vol. 7, No. 2, April 1999.
4267
@@ -63,7 +88,9 @@ pub const MAX_BLOCK_LEN: usize = 254;
6388
/// when encoding a message of `source_len` bytes.
6489
///
6590
/// COBS adds at most one byte per 254 bytes of input (rounded up), and at least
66-
/// one byte for any message including the empty one.
91+
/// one byte for any message including the empty one. In closed form this is
92+
/// $\lceil n/254 \rceil$ for a non-empty message of $n$ bytes, and $1$ for the
93+
/// empty message.
6794
///
6895
/// ```
6996
/// use cobs_codec_rs::encoding_overhead;
@@ -82,7 +109,8 @@ pub const fn encoding_overhead(source_len: usize) -> usize {
82109

83110
/// Returns the maximum possible length, in bytes, of the COBS (or COBS/R)
84111
/// encoding of a message of `source_len` bytes. Useful for sizing an encode
85-
/// buffer.
112+
/// buffer. For a message of $n$ bytes this is $n + \lceil n/254 \rceil$ (and
113+
/// $1$ when $n = 0$).
86114
///
87115
/// ```
88116
/// use cobs_codec_rs::max_encoded_len;

tests/features.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![allow(clippy::pedantic, missing_docs)]
44

55
use cobs_codec_rs::framing::StreamDecoder;
6-
use cobs_codec_rs::{cobs, cobsr, max_encoded_len, DecodeError};
6+
use cobs_codec_rs::{DecodeError, cobs, cobsr, max_encoded_len};
77

88
/// Tiny deterministic xorshift PRNG (keeps the crate dependency-free).
99
struct Rng(u64);
@@ -193,9 +193,10 @@ fn stream_decoder_signals_output_too_small() {
193193
errs.push(e);
194194
}
195195
});
196-
assert!(errs
197-
.iter()
198-
.any(|e| matches!(e, DecodeError::OutputTooSmall)));
196+
assert!(
197+
errs.iter()
198+
.any(|e| matches!(e, DecodeError::OutputTooSmall))
199+
);
199200
}
200201

201202
#[test]

0 commit comments

Comments
 (0)