Subject
compact_str provides CompactString, a memory-efficient drop-in replacement for std::string::String that stores strings of up to 24 bytes (12 on 32-bit) inline on the stack and only spills to the heap for longer strings. Three internal variants — inline, heap-allocated, and a borrowed &'static str — share a single 24-byte layout discriminated by the final byte, which is chosen so that the niche range [218, 255] also makes Option<CompactString> the same size as CompactString. The crate is #![no_std], offers an extensive set of opt-in integrations (serde, borsh, bytes, markup, diesel, sqlx-{mysql,postgres,sqlite}, arbitrary, proptest, quickcheck, rkyv, smallvec, zeroize), and exposes specialized ToCompactString impls for primitive numeric types using castaway for zero-cost compile-time type dispatch.
Methodology
Tools used:
openvet 0.x for workspace creation, claims, annotations, findings, and dependency narratives.
diff (BSD) to compare contents/ against vcs/.
grep -rn to enumerate unsafe blocks, unsafe impl, FFI (extern), filesystem/network/process syscalls, and // SAFETY: comments.
The published compact_str-0.9.1.crate was unpacked and compared against the upstream https://github.com/ParkMyCar/compact_str checkout at the commit recorded in .cargo_vcs_info.json (fbe932e7d03c). The only differences in contents/ versus vcs/ are cargo's standard Cargo.toml normalisation and the addition of Cargo.lock and .cargo_vcs_info.json; the entire src/ tree matches byte-for-byte.
Source review walked all of src/: lib.rs (~2.6k lines, public API surface), the repr/ module (mod.rs, heap.rs, inline.rs, static_str.rs, capacity.rs, iter.rs, last_utf8_char.rs, num.rs, bytes.rs, smallvec.rs, traits.rs), the per-feature integrations in features/, the traits.rs ToCompactString/CompactStringExt definitions, the format_compact! macro, and the unicode_data.rs table adapted from the standard library. Tests in src/tests.rs (~108 attributed tests using proptest, quickcheck, test_case, and test_strategy) and the per-module test submodules were skimmed for coverage of unsafe paths.
The VCS checkout was also inspected for the CI workflows (.github/workflows/ci.yml, fuzz.yml, cross_platform.yml, msrv.yml, clippy.yml) and the fuzz/ crate (libFuzzer target plus AFL++ scenario generator). The crate has no build.rs, no proc-macros ([lib] proc-macro is not set; Cargo.toml explicitly has build = false), and no binaries.
Results
The crate contains no binaries (justifying has-binaries), no build-script (build = false in Cargo.toml and no build.rs, justifying has-build-exec), and no installation-time hooks (cargo has no install scripts, justifying has-install-exec). It performs no filesystem, network, environment-variable, process-execution, JIT, interpreter, or cryptographic work (justifying uses-filesystem, uses-network, uses-environment, uses-exec, uses-jit, uses-interpreter, uses-crypto, impl-crypto, impl-parser, impl-interpreter, impl-jit, impl-protocol, impl-algorithm). No concurrency primitives are implemented and no threads/async are spawned; the only concurrency surface is unsafe impl Send for Drain / Sync for Drain (mirroring the &mut CompactString borrow Drain holds) and unsafe impl Send + Sync for Repr (justifying uses-concurrency, impl-concurrency).
unsafe is extensively used (~165 mentions across the crate; justifying uses-unsafe) but each use is localised, paired with a // SAFETY: justification (~91 such comments), and consistently uses internal invariants (last-byte discriminant, capacity tagging, UTF-8 validity at boundaries) that are themselves enforced at construction time and asserted with static_assertions at compile time and tested with miri in CI (justifying unsafe-documented, unsafe-minimal, unsafe-tested). The single use of inline assembly is an empty no-op shim in repr/mod.rs:840-863 that forces the heap-length field to be eagerly loaded so len() compiles to a conditional move; it is bypassed under miri.
The data structure correctness story is strong: the type's invariants — discriminant byte authoritatively identifies the variant; inline length encoded in the final byte; capacity inlined on 64-bit, optionally on-heap on 32-bit — are stated in code, checked with static_assertions, and exercised by an extensive test surface (justifying datastructure-impl-correct, datastructure-impl-tested). The 0.9.1 release fixes a realloc-layout mismatch UB on heap shrink into the (MAX_SIZE, MIN_HEAP_SIZE) window (see annotation on src/repr/heap.rs:104-214); the fix is regression-tested by test_realloc_shrink_to_min_heap_gap and the rest of the unsafe-heavy code is exercised by property tests, quickcheck, and the dedicated fuzz/ crate kept in the upstream repository: a libFuzzer target plus AFL++ scenario generator running on both x86_64 and ARMv7 in CI (justifying has-fuzz-tests, unsafe-safe, datastructure-impl-safe). Time/space behaviour matches String (O(1) length/capacity, amortized O(1) push with 1.5× growth in amortized_growth, O(n) clone) (justifying datastructure-impl-bounds).
One low-severity finding (FINDING-1) was identified: on powerpc64 (64-bit) the f32/f64 to_compact_string specialization (ryu-backed) disagrees with std::fmt::Display, and the crate works around this by skipping the test rather than disabling the specialization — so users on that target may observe a different float formatting than std. No memory-safety or data-corruption consequence.
No malicious behaviour was identified during review of the source tree, the CI configuration, or the published artefact (justifying is-benign).
Conclusion
compact_str 0.9.1 is a small-string-optimization library with a single, well-defined purpose. Its correctness rests on tightly-controlled unsafe code, but that code is documented at every site, kept minimal, validated under miri, property-tested with proptest and quickcheck, and additionally fuzzed with both libFuzzer and AFL++ in CI. The 0.9.1 release fixes the only known UB (HeapBuffer::realloc layout mismatch on shrink) and adds a regression test that miri exercises directly. The remaining finding is a narrow correctness deviation on powerpc64 that does not affect memory safety. The dependency surface is mostly opt-in integration crates with well-scoped descriptions; mandatory runtime dependencies (castaway, cfg-if, itoa, rustversion, ryu, static_assertions) are widely-used utility crates with no capability footprint of their own.