chore: audit cleanup, CI, cargo-deny, encode fuzz target (0.3.4)
CI / Test (1.93) (push) Canceled after 0s
CI / Test (stable) (push) Canceled after 0s
CI / Test (1.83, legacy-msrv) (push) Canceled after 0s
CI / Clippy (push) Canceled after 0s
CI / Format (push) Canceled after 0s
CI / Doc (push) Canceled after 0s
CI / Cargo Deny (push) Canceled after 0s
CI / Test (1.93) (push) Canceled after 0s
CI / Test (stable) (push) Canceled after 0s
CI / Test (1.83, legacy-msrv) (push) Canceled after 0s
CI / Clippy (push) Canceled after 0s
CI / Format (push) Canceled after 0s
CI / Doc (push) Canceled after 0s
CI / Cargo Deny (push) Canceled after 0s
Simplify encoder exit branch (−41 B code size), add GitHub Actions CI with MSRV matrix, cargo-deny with permissive-only license policy, encode-only fuzz target, and feature coverage across test gates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
11 files changed
+223
-35
No files matched your search
@@ -0,0 +1,69 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test (${{ matrix.rust }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
rust: [stable, "1.93"]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
- run: cargo test
|
||||||
|
|
||||||
|
test-legacy-msrv:
|
||||||
|
name: Test (1.83, legacy-msrv)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: "1.83"
|
||||||
|
- run: cargo test --features legacy-msrv
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
name: Clippy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: clippy
|
||||||
|
- run: cargo clippy -- -D warnings
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
name: Format
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: rustfmt
|
||||||
|
- run: cargo fmt -- --check
|
||||||
|
|
||||||
|
doc:
|
||||||
|
name: Doc
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- run: cargo doc --no-deps
|
||||||
|
|
||||||
|
deny:
|
||||||
|
name: Cargo Deny
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: EmbarkStudios/cargo-deny-action@v2
|
||||||
@@ -1,5 +1,36 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.3.4 — 2026-04-01
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Encode shrunk by 41 bytes** — simplified branch structure in encoder exit
|
||||||
|
path. 388 B encode, 392 B decode, 780 B total (was 821 B). Zero benchmark
|
||||||
|
regressions.
|
||||||
|
- **Clarified decode invariant** — added inline comment explaining the subtle
|
||||||
|
trailing-0x01 COBS rule (end-of-data marker vs zero byte).
|
||||||
|
- **Clippy cleanup** — `saturating_sub` in proptest (cosmetic, test-only).
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **GitHub Actions CI** — tests on stable + MSRV 1.93 + 1.83/legacy-msrv,
|
||||||
|
clippy, fmt, doc, and cargo-deny.
|
||||||
|
- **`cargo-deny` integration** — `deny.toml` with permissive-only license
|
||||||
|
policy, advisory checks, source auditing. Added `just test-deny` gate.
|
||||||
|
- **Encode-only fuzz target** — `fuzz_encode` exercises buffer-too-small
|
||||||
|
paths and validates output properties independently of decode.
|
||||||
|
- **Feature coverage** — `just test-unit` and `just test-clippy` now test
|
||||||
|
both default and `legacy-msrv` features. `just test-doc` builds with
|
||||||
|
`--all-features`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **README accuracy** — overhead description changed from "exactly" to
|
||||||
|
"at most ... plus 1", added miri to test mentions, updated code size
|
||||||
|
numbers.
|
||||||
|
- **CLAUDE.md rewrite** — updated stale API signatures, LOC count, roadmap,
|
||||||
|
dev-deps list, and development commands.
|
||||||
|
|
||||||
## 0.3.3 — 2026-04-01
|
## 0.3.3 — 2026-04-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
1. **Correct** — 100% COBS spec-compliant (Cheshire & Baker 1999). No shortcuts, no deviations.
|
1. **Correct** — 100% COBS spec-compliant (Cheshire & Baker 1999). No shortcuts, no deviations.
|
||||||
2. **Interoperable** — proven byte-for-byte compatibility with `corncobs`, `cobs` crates and Python `cobs` packages.
|
2. **Interoperable** — proven byte-for-byte compatibility with `corncobs`, `cobs` crates and Python `cobs` packages.
|
||||||
3. **Insanely tested** — canonical vectors, property-based tests (proptest), fuzz targets (cargo-fuzz), cross-crate interop, randomized payloads. If you think testing is done, you're 10% done.
|
3. **Insanely tested** — canonical vectors, property-based tests (proptest), fuzz targets (cargo-fuzz), cross-crate interop, miri, mutation testing, randomized payloads. If you think testing is done, you're 10% done.
|
||||||
4. **Fast** — benchmark against every competing implementation. Must be at least as fast, ideally fastest. Benchmarks are CI-enforced.
|
4. **Fast** — benchmark against every competing implementation. Must be at least as fast, ideally fastest. Benchmarks run via `just bench`.
|
||||||
5. **Tiny** — `no_std`, zero-alloc, zero runtime dependencies. ~120 lines of implementation. Runs on 8-bit MCUs and servers alike.
|
5. **Tiny** — `no_std`, zero-alloc, zero runtime dependencies. ~140 lines of implementation. Runs on 8-bit MCUs and servers alike.
|
||||||
6. **Trustworthy** — small enough to audit by hand. No unsafe. No panics in release. Fuzz-hardened.
|
6. **Trustworthy** — small enough to audit by hand. No unsafe. No panics in release. Fuzz-hardened.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
@@ -22,7 +22,7 @@ Single-file library: `src/lib.rs`
|
|||||||
### Public API (3 functions)
|
### Public API (3 functions)
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub fn encode(src: &[u8], dest: &mut [u8]) -> Option<usize>
|
pub const fn encode(src: &[u8], dest: &mut [u8]) -> Option<usize>
|
||||||
pub fn decode(src: &[u8], dest: &mut [u8]) -> Option<usize>
|
pub fn decode(src: &[u8], dest: &mut [u8]) -> Option<usize>
|
||||||
pub const fn max_encoded_len(src_len: usize) -> usize
|
pub const fn max_encoded_len(src_len: usize) -> usize
|
||||||
```
|
```
|
||||||
@@ -32,26 +32,29 @@ pub const fn max_encoded_len(src_len: usize) -> usize
|
|||||||
## Development
|
## Development
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Run all tests
|
# Run all quality gates (tests, clippy, fmt, doc, fuzz, miri, mutants)
|
||||||
cargo test
|
just test
|
||||||
|
|
||||||
|
# Unit + property + interop tests only
|
||||||
|
just test-unit
|
||||||
|
|
||||||
|
# Benchmarks (iai-callgrind, requires valgrind)
|
||||||
|
just bench
|
||||||
|
|
||||||
# Fuzz (requires nightly + cargo-fuzz)
|
# Fuzz (requires nightly + cargo-fuzz)
|
||||||
cd fuzz
|
just test-fuzz
|
||||||
cargo +nightly fuzz run fuzz_decode -- -max_total_time=60
|
|
||||||
cargo +nightly fuzz run fuzz_roundtrip -- -max_total_time=60
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Dev Dependencies (test-only)
|
## Dev Dependencies (test-only)
|
||||||
|
|
||||||
|
- `cobs` — cross-validation against the `cobs` 0.5 crate
|
||||||
- `corncobs` — cross-validation against another COBS implementation
|
- `corncobs` — cross-validation against another COBS implementation
|
||||||
|
- `iai-callgrind` — deterministic instruction-count benchmarks
|
||||||
|
- `mutants` — mutation testing annotations
|
||||||
- `proptest` — property-based testing
|
- `proptest` — property-based testing
|
||||||
- `rand` — randomized test payloads
|
- `rand` — randomized test payloads
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- More interop targets: `cobs` crate, Python `cobs` package
|
|
||||||
- Benchmarks (criterion) vs corncobs, cobs, and others
|
|
||||||
- quickcheck in addition to proptest
|
- quickcheck in addition to proptest
|
||||||
- Even more fuzz targets and edge-case generators
|
- Even more fuzz targets and edge-case generators
|
||||||
- MSRV policy and CI
|
|
||||||
- `#[deny(unsafe_code)]` badge
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ucobs"
|
name = "ucobs"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.93"
|
rust-version = "1.93"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
[Consistent Overhead Byte Stuffing](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing)
|
[Consistent Overhead Byte Stuffing](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing)
|
||||||
(COBS) encodes arbitrary bytes so that `0x00` never appears in the output,
|
(COBS) encodes arbitrary bytes so that `0x00` never appears in the output,
|
||||||
allowing `0x00` to serve as an unambiguous frame delimiter. Overhead is exactly
|
allowing `0x00` to serve as an unambiguous frame delimiter. Overhead is at most
|
||||||
1 byte per 254 input bytes (worst case).
|
1 byte per 254 input bytes, plus 1.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ allowing `0x00` to serve as an unambiguous frame delimiter. Overhead is exactly
|
|||||||
- **100% spec-compliant** — Cheshire & Baker, IEEE/ACM Transactions on Networking, 1999
|
- **100% spec-compliant** — Cheshire & Baker, IEEE/ACM Transactions on Networking, 1999
|
||||||
- **Proven interoperability** — cross-validated against `corncobs`, `cobs`, and Python `cobs`
|
- **Proven interoperability** — cross-validated against `corncobs`, `cobs`, and Python `cobs`
|
||||||
- **Insanely tested** — canonical vectors, property-based tests, fuzz targets,
|
- **Insanely tested** — canonical vectors, property-based tests, fuzz targets,
|
||||||
cross-crate interop, randomized payloads, and more coming
|
cross-crate interop, miri, mutation testing, randomized payloads
|
||||||
|
|
||||||
## Performance
|
## Performance
|
||||||
|
|
||||||
@@ -64,16 +64,16 @@ combined). Run `just bench-size` to reproduce.
|
|||||||
|
|
||||||
| Crate | `encode` | `decode` | Total |
|
| Crate | `encode` | `decode` | Total |
|
||||||
|----------------|--------:|---------:|------:|
|
|----------------|--------:|---------:|------:|
|
||||||
| μCOBS | 429 B | 392 B | 821 B |
|
| μCOBS | 388 B | 392 B | 780 B |
|
||||||
| `cobs` 0.5 | 282 B | 494 B | 776 B |
|
| `cobs` 0.5 | 282 B | 494 B | 776 B |
|
||||||
| `corncobs` 0.1 | 375 B | 262 B | 637 B |
|
| `corncobs` 0.1 | 375 B | 262 B | 637 B |
|
||||||
|
|
||||||
All three crates are under 1 KB. μCOBS is the largest because safe
|
All three crates are under 1 KB. μCOBS and `cobs` are nearly tied;
|
||||||
`const fn` encoding with `copy_from_slice`/memcpy requires `split_at`
|
`corncobs` is the smallest. μCOBS's safe `const fn` encoding with
|
||||||
bounds checks that generate panic paths — the cost of combining
|
`copy_from_slice`/memcpy requires `split_at` bounds checks that
|
||||||
compile-time safety with runtime speed. Embedded users targeting size
|
generate panic paths — the cost of combining compile-time safety with
|
||||||
over speed can build with `opt-level = "s"` which reduces μCOBS to
|
runtime speed. Embedded users targeting size over speed can build with
|
||||||
~738 B.
|
`opt-level = "s"` to shrink further.
|
||||||
|
|
||||||
### Crate properties
|
### Crate properties
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ over speed can build with `opt-level = "s"` which reduces μCOBS to
|
|||||||
| Dead-simple API (3 functions) | **yes** | yes | more surface area |
|
| Dead-simple API (3 functions) | **yes** | yes | more surface area |
|
||||||
| In-place / streaming encode | no | no | **yes** |
|
| In-place / streaming encode | no | no | **yes** |
|
||||||
| `no_std` + zero-alloc by default | **yes** | opt-in | **yes** |
|
| `no_std` + zero-alloc by default | **yes** | opt-in | **yes** |
|
||||||
| Thorough test suite | **111 tests, fuzz, proptest, mutants** | basic | basic |
|
| Thorough test suite | **111 tests, fuzz, proptest, miri, mutants** | basic | basic |
|
||||||
|
|
||||||
**Choose μCOBS** if you want the smallest, most auditable COBS implementation
|
**Choose μCOBS** if you want the smallest, most auditable COBS implementation
|
||||||
with a `const fn` encoder, a dead-simple 3-function API, and leading or tied
|
with a `const fn` encoder, a dead-simple 3-function API, and leading or tied
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
[graph]
|
||||||
|
all-features = true
|
||||||
|
|
||||||
|
[advisories]
|
||||||
|
yanked = "deny"
|
||||||
|
ignore = [
|
||||||
|
# bincode 1.3.3 — transitive dev-dep via iai-callgrind (latest 0.16.1).
|
||||||
|
# Unmaintained but stable and complete; no security issue. Dev-only, never
|
||||||
|
# ships in ucobs. Remove this ignore when iai-callgrind drops bincode.
|
||||||
|
"RUSTSEC-2025-0141",
|
||||||
|
]
|
||||||
|
|
||||||
|
[licenses]
|
||||||
|
# Permissive licenses only. All copyleft (GPL, LGPL, AGPL, MPL, etc.) is denied by omission.
|
||||||
|
allow = [
|
||||||
|
"MIT",
|
||||||
|
"Apache-2.0",
|
||||||
|
"BSD-2-Clause",
|
||||||
|
"BSD-3-Clause",
|
||||||
|
"ISC",
|
||||||
|
"Zlib",
|
||||||
|
"Unlicense",
|
||||||
|
"CC0-1.0",
|
||||||
|
"Unicode-3.0",
|
||||||
|
"Unicode-DFS-2016",
|
||||||
|
]
|
||||||
|
unused-allowed-license = "allow"
|
||||||
|
|
||||||
|
[bans]
|
||||||
|
multiple-versions = "warn"
|
||||||
|
wildcards = "deny"
|
||||||
|
|
||||||
|
[sources]
|
||||||
|
unknown-registry = "deny"
|
||||||
|
unknown-git = "deny"
|
||||||
|
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||||
|
allow-git = []
|
||||||
@@ -30,3 +30,9 @@ name = "fuzz_small_dest"
|
|||||||
path = "fuzz_targets/fuzz_small_dest.rs"
|
path = "fuzz_targets/fuzz_small_dest.rs"
|
||||||
test = false
|
test = false
|
||||||
doc = false
|
doc = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "fuzz_encode"
|
||||||
|
path = "fuzz_targets/fuzz_encode.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
//! Fuzz target: encode arbitrary input into buffers of varying sizes.
|
||||||
|
//! Exercises encode error paths (buffer too small) and validates output properties.
|
||||||
|
#![no_main]
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
|
||||||
|
fuzz_target!(|data: &[u8]| {
|
||||||
|
if data.len() > 1024 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let max = ucobs::max_encoded_len(data.len());
|
||||||
|
|
||||||
|
// Encode into a correctly-sized buffer — must always succeed.
|
||||||
|
let mut buf = vec![0u8; max];
|
||||||
|
let n = ucobs::encode(data, &mut buf)
|
||||||
|
.expect("encode failed with max_encoded_len buffer");
|
||||||
|
let encoded = &buf[..n];
|
||||||
|
|
||||||
|
// Output must never contain 0x00.
|
||||||
|
assert!(!encoded.contains(&0x00), "encoded output contains 0x00");
|
||||||
|
|
||||||
|
// Output length must be bounded by max_encoded_len.
|
||||||
|
assert!(n <= max, "encoded length exceeds max_encoded_len");
|
||||||
|
|
||||||
|
// Output must be at least 1 byte (even empty input encodes to [0x01]).
|
||||||
|
assert!(n >= 1, "encoded length is zero");
|
||||||
|
|
||||||
|
// Encode into every possible undersized buffer — must return None, never panic.
|
||||||
|
for size in 0..n {
|
||||||
|
let mut small = vec![0u8; size];
|
||||||
|
assert_eq!(ucobs::encode(data, &mut small), None);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
default:
|
default:
|
||||||
@just --list
|
@just --list
|
||||||
|
|
||||||
# run ALL quality gates (tests, clippy, fmt check, doc, fuzz, miri, mutants)
|
# run ALL quality gates (tests, clippy, fmt check, doc, deny, fuzz, miri, mutants)
|
||||||
test: test-unit test-clippy test-fmt test-doc test-fuzz test-miri test-mutants
|
test: test-unit test-clippy test-fmt test-doc test-deny test-fuzz test-miri test-mutants
|
||||||
|
|
||||||
# quick compile check (no tests)
|
# quick compile check (no tests)
|
||||||
check:
|
check:
|
||||||
@@ -14,11 +14,13 @@ check:
|
|||||||
# unit + integration + proptest tests (via nextest for parallelism)
|
# unit + integration + proptest tests (via nextest for parallelism)
|
||||||
test-unit:
|
test-unit:
|
||||||
cargo nextest run
|
cargo nextest run
|
||||||
|
cargo nextest run --features legacy-msrv
|
||||||
cargo test --doc
|
cargo test --doc
|
||||||
|
|
||||||
# clippy with all warnings as errors
|
# clippy with all warnings as errors
|
||||||
test-clippy:
|
test-clippy:
|
||||||
cargo clippy -- -D warnings
|
cargo clippy -- -D warnings
|
||||||
|
cargo clippy --features legacy-msrv -- -D warnings
|
||||||
|
|
||||||
# check formatting
|
# check formatting
|
||||||
test-fmt:
|
test-fmt:
|
||||||
@@ -26,11 +28,16 @@ test-fmt:
|
|||||||
|
|
||||||
# doc build (catches broken doc links)
|
# doc build (catches broken doc links)
|
||||||
test-doc:
|
test-doc:
|
||||||
cargo doc --no-deps
|
cargo doc --no-deps --all-features
|
||||||
|
|
||||||
|
# license and advisory audit (requires cargo-deny)
|
||||||
|
test-deny:
|
||||||
|
cargo deny check
|
||||||
|
|
||||||
# fuzz all targets (60s each, requires nightly + cargo-fuzz)
|
# fuzz all targets (60s each, requires nightly + cargo-fuzz)
|
||||||
test-fuzz:
|
test-fuzz:
|
||||||
cd fuzz && cargo +nightly fuzz run fuzz_decode -- -max_total_time=60
|
cd fuzz && cargo +nightly fuzz run fuzz_decode -- -max_total_time=60
|
||||||
|
cd fuzz && cargo +nightly fuzz run fuzz_encode -- -max_total_time=60
|
||||||
cd fuzz && cargo +nightly fuzz run fuzz_roundtrip -- -max_total_time=60
|
cd fuzz && cargo +nightly fuzz run fuzz_roundtrip -- -max_total_time=60
|
||||||
cd fuzz && cargo +nightly fuzz run fuzz_small_dest -- -max_total_time=60
|
cd fuzz && cargo +nightly fuzz run fuzz_small_dest -- -max_total_time=60
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
[tools]
|
[tools]
|
||||||
"cargo:cargo-nextest" = "latest"
|
rust = "1.93"
|
||||||
|
"cargo:cargo-deny" = "latest"
|
||||||
|
"cargo:cargo-fuzz" = "latest"
|
||||||
"cargo:cargo-mutants" = "latest"
|
"cargo:cargo-mutants" = "latest"
|
||||||
|
"cargo:cargo-nextest" = "latest"
|
||||||
"cargo:iai-callgrind-runner" = "latest"
|
"cargo:iai-callgrind-runner" = "latest"
|
||||||
+5
-6
@@ -256,14 +256,10 @@ pub const fn encode(src: &[u8], dest: &mut [u8]) -> Option<usize> {
|
|||||||
}
|
}
|
||||||
si += run;
|
si += run;
|
||||||
|
|
||||||
if full_block {
|
|
||||||
if si >= src.len() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if si >= src.len() {
|
if si >= src.len() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if !full_block {
|
||||||
si += 1; // skip the zero byte
|
si += 1; // skip the zero byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,6 +311,9 @@ pub fn decode(src: &[u8], dest: &mut [u8]) -> Option<usize> {
|
|||||||
src = rest;
|
src = rest;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
// If more data follows, every 0x01 represents a zero byte.
|
||||||
|
// If the stream ends here, the final 0x01 is the end-of-data
|
||||||
|
// marker, not a zero — so emit one fewer.
|
||||||
let zeros = if !src.is_empty() { count } else { count - 1 };
|
let zeros = if !src.is_empty() { count } else { count - 1 };
|
||||||
if di + zeros > dest.len() {
|
if di + zeros > dest.len() {
|
||||||
return None;
|
return None;
|
||||||
@@ -1259,7 +1258,7 @@ mod proptests {
|
|||||||
shrink in 1usize..256,
|
shrink in 1usize..256,
|
||||||
) {
|
) {
|
||||||
let max = max_encoded_len(data.len());
|
let max = max_encoded_len(data.len());
|
||||||
let dest_size = if shrink >= max { 0 } else { max - shrink };
|
let dest_size = max.saturating_sub(shrink);
|
||||||
let mut buf = vec![0u8; dest_size];
|
let mut buf = vec![0u8; dest_size];
|
||||||
let _ = encode(&data, &mut buf); // may return None, must not panic
|
let _ = encode(&data, &mut buf); // may return None, must not panic
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user