Files
oak-editor/crates/oakcommon/README.md
T
Mike-Solar 013a175707 refactor: workspace layout — crates/, app at root, legacy C++ removed
Single mechanical restructure commit:
- root Cargo.toml = oakapp bin + workspace; one cargo build produces
  oakapp, oak-cli, oak-worker, liboakengine.dylib
- app/rust/src -> src/ (app at repo root, no rust/ nesting)
- src/<mod>/rust -> crates/oak<mod>; src/oakcore-rs -> crates/oakcore;
  src/bindings/oakotio -> crates/oakotio; src/engine/rust ->
  crates/oakengine (keeps cdylib+staticlib+rlib)
- public C headers include/<mod>/ -> crates/oakengine/include/<mod>/
- OFX SDK headers vendored into crates/oakplugin/ofx/ (HostSupport gone)
- legacy deleted: old src/ C++ modules, engine/, core/, ffmpeg_bridge/,
  app/ (Qt), cli/worker C++, root CMakeLists, third_party/KDDockWidgets
  submodule, otio-install, all build-* output (~40GB)
- oakstorage kept but excluded from the workspace (skeleton w/ todos);
  gpui excluded (own workspace)
- verified: cargo build green, cargo test --workspace 1845/0
  (with the documented OCIO_RS_* env override for the homebrew OCIO)
2026-08-10 20:24:25 +08:00

105 lines
5.8 KiB
Markdown

# oakcommon Rust crate
> Status: **implemented**. All `include/common/*.h` contracts are
> implemented in Rust and covered by unit + C ABI integration tests
> (see [Testing](#testing)).
## Scope
Replaces the C++ oakcommon module (`src/common/src`): config store,
command-line parser, XML stream reader/writer, file functions,
debug/logging, ffmpeg/OCIO/OIIO utility queries, video/subtitle
params, color transform, misc utilities. Pure leaf module — depends
only on `oakcore-rs`, `quick-xml`, `log`, `ocio-rs`, `image`, and
system libraries.
Public contract: `include/common/*.h` (18 headers) — frozen,
implemented verbatim by `src/ffi.rs`.
## Third-party crates
| Crate | Version | License | Status |
|---|---|---|---|
| `quick-xml` | 0.41 | MIT | adopted — XML reader/writer (`xmlutils.rs`) |
| `log` | 0.4 | MIT / Apache-2.0 | adopted — logging facade (`debug.rs`); the stderr sink is retained as the always-available backend |
| `ocio-rs` | 0.2.1 | BSD-3-Clause | adopted — real OpenColorIO access for `ocioutils.rs` (`OcioConfig`/`OcioProcessor`, `BitDepth` mapping). Pulled in via `ocio-sys` built with `OCIO_RS_ENABLE_REAL=1` against the Homebrew OCIO install (see `.cargo/config.toml`) |
| `image` | 0.25 | MIT / Apache-2.0 | adopted — per-channel bit-depth tables and 32-bit float TIFF I/O for `oiioutils.rs` (`image_color_type_for`/`bits_per_channel`, `F32Image`). Default features off, `tiff` only |
| `oakcore-rs` | path | GPL-3.0 | adopted — `Rational::from_double` (the C++ `Rational::from_double` port of FFmpeg's `av_d2q`) for `get_pixel_aspect_ratio`; a hand-written port kept in the leaf crate instead of pulling in `ffmpeg-next` |
| `serde_json` | — | MIT / Apache-2.0 | **evaluated, not adopted** — the ConfigStore format is INI (QSettings-style `key=value` with `[group]` sections, `%g` doubles), not JSON; switching would break C++/Rust file interop |
| `pico-args` / `clap` | — | MIT / Apache-2.0 | **evaluated, not adopted**`commandlineparser.rs` must keep exact C++ quirks (case-insensitive names, first-match-wins, last-value-wins, argv[0] skipping, truncating getter copies, borrowed C ABI handles) that a generic parser cannot express without changing the C ABI shape |
## Architectural decisions
1. **Leaf module discipline**: no `bridge/` to other oak modules.
FFmpeg is reached through `ffmpeg_bridge`'s C ABI (narrow
`extern "C"` blocks in `ffmpegutils.rs`); OCIO and OIIO access is
pure Rust via the crates.io bindings listed in the table above
(`ocioutils.rs`, `oiioutils.rs`).
2. **`olive::Variant` disappears**: it exists in C++ only because
QVariant left a hole. Rust modules use closed enums; nothing in
common needs it. `variant.{h,cpp}` (C++) is retired when all
consumers are Rust.
3. **XML**: `XmlStreamReader/Writer` keep the C++ streaming API shape
(the C ABI is built on it), implemented over quick-xml — behavior
(attribute order, error semantics) pinned by tests against the C++
oracle.
4. **Config**: the ConfigStore is **INI-backed** (QSettings-style
`key=value` with `[group]` sections, `;`/`#` comments, `%g`
double formatting), keeping the exact C++ file format and lookup
order (user config → app defaults). It is *not* JSON — an earlier
draft described it as JSON-backed, which was wrong; that claim was
removed from this document.
5. **Logging**: `debug.rs` provides the leveled logger
(qWarning/qDebug/qCritical/qInfo replacement) with a printf-style C
ABI. Every record is written to stderr (the C++ `stderr_sink`
parity) and additionally forwarded to the `log` crate's global
logger when the host has installed one. oakcommon never installs a
global logger itself — the C ABI is loaded into hosts that set
their own, and `log::set_logger` can only be called once per
process.
6. **OCIO / OIIO / FFmpeg**: `ocioutils.rs` talks to real OpenColorIO
through the crates.io `ocio-rs` bindings (`OcioConfig`/`OcioProcessor`,
`BitDepth` enum — no hand-written constant tables); `oiioutils.rs`
derives its OIIO base-type mapping from the `image` crate's color-type
tables (HALF pinned from the frozen OIIO table — `image` has no f16
sample type) and converts aspect ratios with
`oakcore_rs::Rational::from_double` — a hand-written port of FFmpeg's
`av_d2q` matching the C++ `Rational::from_double` exactly, kept in the
leaf crate rather than adding `ffmpeg-next`/`ffmpeg-sys-next` (narrow
extern C discipline). 32-bit float image I/O (`F32Image`) is pure
`image`. All adopted crates are registered in the table above.
## Layout
```
src/
lib.rs crate doc + module map
error.rs error codes (include/common/error.h)
handle.rs refcounted-handle scaffolding
configstore.rs INI config (include/common/config.h)
commandlineparser.rs
xmlutils.rs streaming XML reader/writer
filefunctions.rs file/dir helpers
debug.rs leveled logging
ffmpegutils.rs pixfmt/samplefmt mapping (via ffmpeg_bridge C ABI)
ocioutils.rs OCIO queries
oiioutils.rs OIIO queries
videoparams.rs VideoParams plain data + queries
subtitleparams.rs SubtitleParams
colortransform.rs ColorTransform plain data
miscutils.rs misc (loop mode, drop behavior, power, current…)
ffi.rs export layer (one submodule per public header)
tests/ contract tests per module
```
## Testing
`cargo test --release --features test-stubs` runs the full suite:
unit tests, C ABI contract tests, and the integration tests (incl.
`tests/ffi_ffmpegutils.rs`). The `test-stubs` feature substitutes the
in-crate ffmpeg_bridge mock (`fb_find_best_pix_fmt_of_list` stub, see
`src/ffmpegutils.rs`) so the C ABI tests link without
libffmpeg_bridge; without the feature that symbol is imported from
`ffmpeg_bridge` at link time. This mirrors the `test-stubs`
convention of oakplugin / oaktimeline.