refactor: purge CHandle from module internals (M14 R5)
Module-internal object references are Rust types now (values, Arc, Mutex); CHandle remains only at the oakengine C-ABI boundary: - oakundo: the global stack holds UndoStack/UndoCommand values directly (stack token is the static's address) - oaktimeline: marker/workarea boxes carry Arc<Mutex<T>>; commands share the same allocation through Arc clones (readers in oakengine stubs and the app's graphops updated to lock) - oaktask/oakstorage: sessions, write-through bindings and the database backend pass ProjectArc; the Session drops its manual release bookkeeping; nodeutil keeps the CHandle<->Arc boundary conversion (release_project restored for the app) - oakcodec: handle.rs deleted outright (no facade entry needed it); texture/block placeholders are unit structs - oakrender: copier's project handle is an identity u64; alive-count machinery removed; handle.rs is make_owned/get/get_mut only - oakplugin: the instance registry is gone (its unregister key never matched, leaking weak entries); handle.rs is the RefBox boundary type - oaknode/oakcommon: only dead guard/borrow helpers removed; external payload handles (texture/processor) documented as the boundary Flake hunts landed along the way: the audio recording test serializes on the shared manager lock with a normalized state; the autocacher cancel test uses a slow producer so cancellation is deterministic.
This commit is contained in:
+33
-34
@@ -1,13 +1,17 @@
|
||||
# oakcodec Rust crate
|
||||
|
||||
> Status: **implemented**. Implements `include/codec/*.h` verbatim
|
||||
> (`src/ffi/`); every export has success + failure-path tests
|
||||
> (`cargo test`: unit tests in `src/ffi/*.rs`, the contract tests in
|
||||
> `tests/`, and real-media tests in `src/realmedia_tests.rs`). The FFmpeg
|
||||
> engine is fully implemented through the [`ffmpeg-next`] crate (decode,
|
||||
> probe, audio conform, encode); the OIIO engine remains a stub in this
|
||||
> build. This crate mirrors the `crates/oaknode/` template (same FFI
|
||||
> discipline, same testing layers).
|
||||
> Status: **implemented**. Implements the `include/codec/*.h` contract;
|
||||
> every function has success + failure-path tests (`cargo test`: unit
|
||||
> tests in `src/`, the contract tests in `tests/`, and real-media tests
|
||||
> in `src/realmedia_tests.rs`). The FFmpeg engine is fully implemented
|
||||
> through the [`ffmpeg-next`] crate (decode, probe, audio conform,
|
||||
> encode); the OIIO engine remains a stub in this build.
|
||||
>
|
||||
> Single-lib unification (M14, `docs/zh/plans/riir/single-lib.md`): the
|
||||
> C-ABI export layer (`src/ffi.rs`) and the module-crossing bridge
|
||||
> (`src/bridge/`) are gone. Other module crates and the oakengine facade
|
||||
> call this crate's modules directly; the facade (`crates/oakengine`)
|
||||
> serves the frozen `include/codec/*.h` functions.
|
||||
|
||||
## Scope
|
||||
|
||||
@@ -18,20 +22,18 @@ conform and proxy generation managers, export format/codec tables,
|
||||
encoding parameters, and the background-task submit hook.
|
||||
|
||||
Public contract: `include/codec/*.h` (7 headers: frame.h, decoder.h,
|
||||
encoder.h, conform.h, proxy.h, task.h, error.h) — frozen, implemented
|
||||
verbatim by `src/ffi.rs`. Interim state (pre-M8) is documented in
|
||||
encoder.h, conform.h, proxy.h, task.h, error.h) — frozen, served by the
|
||||
oakengine facade. Interim state (pre-M8) is documented in
|
||||
`src/codec/NOTES.md`: conform/proxy work is delegated to the global
|
||||
task submit callback and otherwise reports unavailable, never crashes
|
||||
and never blocks.
|
||||
|
||||
## Key architectural decisions (C++ → Rust mapping)
|
||||
|
||||
1. **`shared_ptr` → refcounted `RefBox` handle.** The C++ `Frame`/
|
||||
`Decoder`/`Encoder` objects are heap boxes behind the neutral
|
||||
by-value handle struct `{ctx, addref, release, abi_version}` (see
|
||||
`handle.rs`), exactly as oaknode/oakplugin do. Handles are
|
||||
deliberately duplicated per module: the function pointers always
|
||||
point into the DLL that created the object.
|
||||
1. **`shared_ptr` → `Arc`.** The C++ `Frame`/`Decoder`/`Encoder`
|
||||
objects are handed around as plain Rust values (`Frame`) or
|
||||
`Arc<dyn Decoder>` / `Arc<dyn Encoder>`. No refcounted C-handle
|
||||
scaffolding remains (the former `handle.rs` was deleted in M14 R5).
|
||||
2. **Inheritance → traits.** The C++ `Decoder`/`Encoder` abstract
|
||||
bases plus their FFmpeg/OIIO subclasses become a Rust trait with
|
||||
two implementors. The probe/dispatch (decide which implementation
|
||||
@@ -39,15 +41,14 @@ and never blocks.
|
||||
`PixelFormat`/`SampleFormat` support is a trait query, not a
|
||||
virtual chain.
|
||||
3. **`Frame` owns its params by value.** `olive::Frame` wraps an
|
||||
`OakVideoParams` handle (an oakcommon by-value handle, NOT owned by
|
||||
codec) plus a `Vec<u8>` pixel buffer. In Rust the params are held as
|
||||
the oakcommon handle (refcounted through `bridge::common`) so the
|
||||
byte-level ABI stays unchanged; the buffer is a plain `Vec<u8>`.
|
||||
4. **No adapter layer.** Codec calls other modules' C ABIs directly
|
||||
(`bridge/common.rs`, `bridge/render.rs`), keeping the 2026-08
|
||||
`OakVideoParams` handle plus a `Vec<u8>` pixel buffer. In Rust the
|
||||
params are held as an `oakcommon::videoparams::VideoParams` value
|
||||
(single-lib unification dropped the refcounted oakcommon handle);
|
||||
the buffer is a plain `Vec<u8>`.
|
||||
4. **No adapter layer.** Codec calls the other module crates directly
|
||||
(`oakcommon`, `oakcore-rs`, `oakffmpeg-link`), keeping the 2026-08
|
||||
decision recorded in NOTES.md §6. Only genuinely repeated
|
||||
conversions survive as small module-local helpers (e.g.
|
||||
`fill_render_params`, `cancel_atom_is_cancelled`).
|
||||
conversions survive as small module-local helpers.
|
||||
5. **XML stays on the C++ side.** `EncodingParams::load/save` use
|
||||
oakcommon's C++ `XmlStreamWriter/Reader` classes
|
||||
(`src/common/src/xmlutils.h`), exactly as oaknode/oakrender do —
|
||||
@@ -58,8 +59,8 @@ and never blocks.
|
||||
7. **Enum values are the C contract.** `ExportFormat::Format`,
|
||||
`ExportCodec::Codec`, `Interlacing`, `VideoScalingMethod`,
|
||||
`SampleFormat::Format` all stay as the raw int values the C ABI
|
||||
documents (oakengine/encoding.h), so `ffi.rs` marshals them without
|
||||
translation.
|
||||
documents (oakengine/encoding.h), so the facade marshals them
|
||||
without translation.
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -67,8 +68,7 @@ and never blocks.
|
||||
src/
|
||||
lib.rs crate doc + module map
|
||||
error.rs error codes (mirrors include/codec/error.h)
|
||||
handle.rs refcounted-handle scaffolding (same pattern as node)
|
||||
frame.rs Frame (CPU pixel buffer + OakVideoParams handle)
|
||||
frame.rs Frame (CPU pixel buffer + VideoParams value)
|
||||
framemanager.rs FrameManager (buffer pool + background GC thread)
|
||||
decoder.rs Decoder trait + CodecStream + RenderMode + probe
|
||||
ffmpeg.rs FFmpegDecoder / FFmpegEncoder (ffmpeg-next)
|
||||
@@ -85,17 +85,16 @@ src/
|
||||
footagedescription.rs FootageDescription (codec-internal stream desc)
|
||||
planarfiledevice.rs PlanarFileDevice (stdio plane-channel I/O)
|
||||
realmedia_tests.rs real-media tests (demo.mp4, H.264 round-trip)
|
||||
bridge/ C ABI imports: common.rs, render.rs
|
||||
ffi.rs include/codec/*.h export layer
|
||||
tests/ contract + golden tests (see test section below)
|
||||
```
|
||||
|
||||
## Hard rules for the implementer
|
||||
|
||||
1. Every `extern "C"` body goes through `handle::guard*`; no panic
|
||||
crosses FFI.
|
||||
2. The handle is the only way out of the crate; the public API never
|
||||
hands out raw `&Frame`/`&Decoder` references.
|
||||
1. No panics cross a module boundary: the facade wraps every call in
|
||||
its panic-catching shims, and callback types stay `unsafe extern
|
||||
"C"` with panic-free bodies.
|
||||
2. Objects leave the crate only as Rust types (`Arc`, values, `&`
|
||||
refs); raw handles exist solely inside the facade.
|
||||
3. Behavior parity with C++ is proven by the unchanged C ABI test
|
||||
suite (`src/codec/tests`) plus the contract tests in `tests/`.
|
||||
4. Where C++ behavior is genuinely load-bearing but ugly, port the
|
||||
|
||||
Reference in New Issue
Block a user