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)
oakstorage Rust crate (declaration draft, for review)
Status: declaration draft. Signatures + doc comments are the spec; every body is
todo!(). Manual: docs/zh/plans/riir/M10-oakstorage.md.
Scope
Project persistence — the single module that knows where projects come
from and where they are saved to. Backends are pluggable via a manual
vtable; shipping in this pass: ove-xml (the existing XML project
format), otio (via the native oakotio crate), and database
(PostgreSQL + SQLite). Consumers never branch on backend.
Architectural decisions
- URI dispatch, not file paths. Every entry point takes a URI:
file:///…proj.ove/file:///…proj.otio/oakdb+sqlite:///path/to.db/oakdb+pg://host:port/dbname?user=…. The core resolves scheme + backendcan_handlearbitration (M10 §2.3). - Manual vtable backends (
backend.rsStorageBackendtrait = the M10 C vtable's Rust shape). The public C ABI vtable (oakstorage_backend_register) accepts foreign (C-side) backends; in-crate backends implement the Rust trait directly. - The graph (de)serialization itself stays in oaknode — every
backend calls the oaknode C ABI (
oaknode_serializer_*family) throughbridge::nodeto fetch/rebuild the in-memory graph; backends own framing: container bytes, schema, versioning, compression, sessions. - Database backend shares one logical schema across PostgreSQL
and SQLite via SeaORM (
sea-ormcrate, sqlx-postgres + sqlx-sqlite features): a private current-thread tokio runtime drives the async SeaORM API behind the synchronous C ABI; the entity set is minimal (projects table: id, name, payload blob, version, timestamps). Schema management (create-if-missing, migrate) is backend-internal. The graph payload is the same serialized form the ove-xml backend uses — one serialization truth, two containers. - No callbacks/events (M10: synchronous commands only; the caller — oaktask/facade — owns progress reporting).
- Errors follow the project -MMCCCC scheme, module 10
(
-100001…); the M10 positive info codes (TOO_OLD/TOO_NEW/…) are kept verbatim.
Layout
src/
lib.rs crate doc + module map
error.rs error/info codes (M10 §2.1, -MMCCCC module 10)
handle.rs refcounted-handle scaffolding
uri.rs URI parsing/classification
session.rs StorageProject session (open/take/uri)
registry.rs backend registry (register/unregister/arbitrate)
backend.rs StorageBackend trait + C vtable marshalling
backends/
ove_xml.rs built-in .ove XML backend (via bridge::node)
otio.rs built-in .otio backend (via oakotio)
bridge/
node.rs oaknode C ABI imports (serializer family)
ffi.rs export layer (M10 §2.2 verbatim)
tests/ contract tests incl. the pluggability proof