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)
2.9 KiB
oakundo Rust crate
Status: implemented. Ports the C++ oakundo module (
src/undo/src) to Rust behind its frozen C ABI (include/undo/*.h). Template followscrates/oakplugin.
Scope
Replaces the C++ oakundo module (src/undo/src): undoable commands
and the undo/redo history stack. Public contract: include/undo/*.h
(3 headers: error.h, undocommand.h, undostack.h) — frozen,
implemented verbatim by src/ffi.rs.
Architectural decisions
- Vtable-command pattern is the centerpiece. In C++ other modules
subclass
olive::UndoCommand(redo()/undo()overrides) and plug themselves in polymorphically. Rust has no inheritance, so the C ABI already models exactly this withOakUndoCommandVtable { redo, undo, free_fn }plus a caller-owneduserdatapointer. The safe layer's [undocommand::CommandKind] is the direct analog: either a caller-defined vtable command (function pointers + userdata) or a [undocommand::MultiUndoCommand] composite. Domain logic dispatches on the vtable the same way the C++ virtual dispatch does. - Modified-state callbacks are intentionally not part of the C ABI.
The C++
UndoCommand::redo_and_set_modifiedpair records/restores a project dirty flag viastd::functionaccessors. The public headers expose none of this; the stack drives state viadone_on the safe type instead, and the flag callbacks are left as a documented future extension. UndoStackstate machine is modeled directly on the C++: two deques —commands_(done, oldest at front) andundone_commands_(most-recently-undone at front);pushclears any redoable tail, executes redo, and drops the oldest when the cap (200) is exceeded;jumpclamps and walks viaundo/redo. The fresh stack holds a single "New/Open Project" empty command socan_undois false at the bottom (perundostack.cpp).- No merge semantics.
include/undo/*.handsrc/undo/src/*define nomerge_with/can_merge; commands are never coalesced. Tests reflect this (no merge tests).
Layout
src/
lib.rs crate doc + module map
error.rs error codes (include/undo/error.h)
handle.rs refcounted-handle scaffolding (OAKUNDO_ABI_VERSION=1)
undocommand.rs UndoCommand / vtable command / MultiUndoCommand
undostack.rs UndoStack + empty bottom command
ffi.rs export layer (one submodule per public header)
tests/ contract tests per module
error.h exports macros only and is folded into ffi.rs's preamble
(no own submodule), matching the codec crate convention.
Dependency policy
Prefer mature third-party crates (MIT/Apache-2.0/BSD, GPL-compatible) over hand-rolling; register each addition (name + reason) here. Large existing C++ libraries (OTIO, OCIO, OIIO, FFmpeg) are NEVER rewritten — they are consumed through their C ABI / bridge layers.