feat: add benchmarks, justfile, optimize throughput, harden quality gates
Benchmarking & comparison: - Add criterion benchmarks (ucobs vs cobs 0.3 vs corncobs 0.1) - Add Python cobs benchmark script - Add performance comparison section to README with full results Performance: - Rewrite encode to scan-and-bulk-copy via copy_from_slice - Rewrite decode to bulk-copy via copy_from_slice - ~2-4x throughput improvement; now matches corncobs on most workloads Quality hardening: - Add #![forbid(unsafe_code)], #![warn(missing_docs)], #[must_use] - Add [lints.rust] unsafe_code = "forbid" in Cargo.toml - Add rust-version (MSRV) = "1.56" - Add docs.rs metadata - 106 tests: 80 unit/corpus + 25 property tests (25k cases each = 625k total) - External test vectors from: Wikipedia, Cheshire & Baker paper, nanocobs, cobs-c, cobs2-rs, Jacques Fortier, Python cobs package - Add fuzz_small_dest fuzz target (encode/decode with undersized buffers) - Improve doc examples to show sentinel append/strip convention Infrastructure: - Add justfile with test (nextest), check, bench, fuzz, miri, fmt targets - cargo-nextest for parallel test execution - Update .gitignore for Python cache files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
10 files changed
+1187
-99
No files matched your search
@@ -24,3 +24,9 @@ name = "fuzz_roundtrip"
|
||||
path = "fuzz_targets/fuzz_roundtrip.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_small_dest"
|
||||
path = "fuzz_targets/fuzz_small_dest.rs"
|
||||
test = false
|
||||
doc = false
|
||||
@@ -0,0 +1,36 @@
|
||||
//! Fuzz target: encode and decode with undersized destination buffers.
|
||||
//! Must never panic — should return None when dest is too small.
|
||||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if data.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Split fuzz input: first byte selects dest size, rest is payload.
|
||||
let dest_size = data[0] as usize;
|
||||
let payload = &data[1..];
|
||||
|
||||
// Encode with a potentially too-small buffer.
|
||||
let mut enc_buf = vec![0u8; dest_size];
|
||||
let enc_result = ucobs::encode(payload, &mut enc_buf);
|
||||
|
||||
if let Some(enc_len) = enc_result {
|
||||
let encoded = &enc_buf[..enc_len];
|
||||
|
||||
// Encoded output must never contain 0x00.
|
||||
assert!(!encoded.contains(&0x00), "encoded contains sentinel");
|
||||
|
||||
// Decode with a potentially too-small buffer.
|
||||
let mut dec_buf = vec![0u8; dest_size];
|
||||
let dec_result = ucobs::decode(encoded, &mut dec_buf);
|
||||
|
||||
if let Some(dec_len) = dec_result {
|
||||
assert_eq!(
|
||||
&dec_buf[..dec_len], payload,
|
||||
"round-trip mismatch with small buffers"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user