ADR-1063: Rust clippy strictness — scoped bindings suppression, unsafe_op lint, no panicking Default¶
- Status: Accepted
- Date: 2026-06-06
- Deciders: Lusoris
- Tags:
rust,lint,safety,workspace
Context¶
The VMAFX Rust workspace (bindings/rust/vmafx-sys, bindings/rust/vmafx, core/src/feature/rust/tad) accumulated three categories of clippy / coding-standard debt that a round-11 audit surfaced:
-
Panicking
Defaultimpl in library code (vmafx-sys/src/safe.rs):VmafContext::DefaultcalledSelf::new().expect(...), meaning any downstream code that callsDefault::default()could panic on an out-of-memory or misconfigured system. In library crates, hidden panic paths violate the principle of giving callers error-handling control. -
Blanket
#![allow(clippy::all)]covering hand-written code (vmafx-sys/src/lib.rs): The crate root applied#![allow(clippy::all)]at the crate level to suppress C-naming noise from the bindgen-generated output. This suppression bled intopub mod safe;, silencing all clippy diagnostics on the hand-written safe wrapper. -
Missing
#: Without this lint, anunsafe fnbody is implicitly allowed to perform any unsafe operation without an explicitunsafe {}block, making auditing significantly harder. -
No
clippy::expect_used/clippy::unwrap_usedwarning in the idiomatic bindings crate (bindings/rust/vmafx): Thevmafxcrate is the public-facing API layer; undeclaredunwrap/expectcalls in library code (outside test modules) should be surfaced at compile time.
Decision¶
We will apply the following four targeted fixes:
-
Remove
VmafContext::Defaultfromvmafx-sys/src/safe.rs. Callers that want a default-configured context must callVmafContext::new()directly and handle theResult. A// NOTE:comment explains the deliberate omission. -
Scope
#![allow(clippy::all)]to the generated bindings sub-module invmafx-sys/src/lib.rs. The generated output is wrapped in a privatemod bindingscarrying the lint suppressions;pub use bindings::*re-exports the symbols at the crate root so existing callers require no changes. Thepub mod safe;declaration is now at crate root and NOT covered by the allow. -
Add
#![deny(unsafe_op_in_unsafe_fn)]tovmafx-sys/src/safe.rs(as a module-level inner attribute) and tocore/src/feature/rust/tad/src/lib.rs(as a crate-level inner attribute). -
Add
#![warn(clippy::expect_used)]and#![warn(clippy::unwrap_used)]tobindings/rust/vmafx/src/lib.rs. Test modules that legitimately call.expect()and.unwrap_err()carry#[allow(clippy::expect_used, clippy::unwrap_used)]on themod testsblock.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
Keep Default but add # Panics doc | Documents the hazard | Does not remove it; callers still trigger it inadvertently | Cosmetic fix, not structural |
#[path] attribute for generated file | Same scoping | Syntactically awkward | include! inside a module is idiomatic for generated code |
Deny clippy::expect_used at workspace level | Maximum strictness | Requires blanket allows in build.rs and integration test files | Crate-level is the right granularity |
Consequences¶
- Positive:
unsafe_op_in_unsafe_fndeny makes each unsafe operation auditable in isolation. Removing the panickingDefaulteliminates a hidden abort path. Scoping the clippy suppression means future edits tosafe.rsare checked by the full clippy suite. - Negative: Downstream callers that relied on
VmafContext::default()(none identified in-tree) must switch toVmafContext::new(). - Neutral / follow-ups: The
vmafxcrate's#![warn(clippy::expect_used)]will flag any futureexpect()added outside a test module — this is intentional and acts as an ongoing gate.
References¶
- ADR-0702:
vmafx-sysFFI crate introduction. - ADR-0707: TAD feature extractor (
vmafx-tadcbindgen pilot). - ADR-0929:
vmafxsafe bindings crate introduction. - Round-11 Rust clippy audit (r11-rust-clippy parallel push agent).