Rust context close and retry¶
The safe Rust wrappers treat context teardown as an ownership transition, not as an infallible destructor. This matters for GPU-backed contexts: libvmaf can return an error while it still owns streams, modules, and model references.
Both Rust crates expose the same close protocol:
| Crate | Active context | Retry-only error token |
|---|---|---|
vmafx | Context<'a> | ContextCloseError<'a> |
vmafx-sys::safe | VmafContext<'a> | VmafContextCloseError<'a> |
Call close(self) when teardown errors need to be handled explicitly. Exact zero is the only success value. Any nonzero result, including an unexpected positive status, returns the retry-only token and preserves the native context:
match context.close() {
Ok(()) => {
// The native context and all registered-model borrows are released.
}
Err(pending) => {
eprintln!("initial close failed: {}", pending.error());
match pending.retry() {
Ok(()) => {
// The retry completed teardown.
}
Err(still_pending) => {
eprintln!("close retry failed; first error: {}", still_pending.error());
// The one-retry budget is exhausted. Dropping this token
// aborts without making a third native close call.
drop(still_pending);
}
}
}
}
After close starts, scoring cannot resume. The error token deliberately exposes only error() and the consuming retry() method. A failed retry returns the token again, but the one-retry budget is then exhausted. error() continues to report the first close error; the retry result never replaces it. Calling retry() again does not call native code and returns the same token.
libvmaf owns a reference to every model registered with a context (ADR-1755), so a model no longer has to outlive a teardown-pending native context. The 'a lifetime on Context and on the retry token is kept so existing code compiles unchanged; it is now conservative, not load-bearing for soundness.
Drop behavior¶
Explicit close is recommended whenever the application can report or recover from teardown failures. Drop never aborts the process:
- Dropping an active context makes a close attempt and one bounded retry.
- Dropping a fresh retry token consumes its one permitted retry.
- If the retry fails, or the token was already retried, the native context is leaked: no further close call is made, one line goes to stderr, and the process carries on. The leaked context holds no pointer into memory Rust can free, because libvmaf owns a reference to each model it mounted.
The low-level raw FFI (use vmafx_sys::*) does not provide this ownership guard. Raw callers must keep the VmafContext pointer and every imported backend dependency alive until vmaf_close returns exactly zero. Models are owned by the context once registered.
See the Rust development guide for crate setup and the vmaf_close C contract for the underlying native API.