From e1423553c7bdbe0e556f725f2129b41df748a3b4 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Mon, 10 Aug 2026 17:48:13 +0800 Subject: [PATCH] =?UTF-8?q?refactor(engine):=20single-lib=20phase=201=20?= =?UTF-8?q?=E2=80=94=20direct=20Rust=20calls=20across=20the=20facade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - unify CHandle in oakcore-rs (all crates re-export it) - facade bridge: 618/624 externs converted to direct module calls - signature-drift fixes surfaced by direct calls (videoparams, seconds, sync estimate, POD unification) - dead node<->render call sites removed; cancelatom -> oakcommon - node bridge/undo -> oakundo direct calls - docs/zh/plans/riir/single-lib.md: design + live status --- docs/zh/plans/riir/single-lib.md | 400 +++ src/audio/rust/src/handle.rs | 48 +- src/audio/rust/tests/ffi_test.rs | 3 +- src/audio/rust/tests/handle_test.rs | 3 +- src/codec/rust/src/handle.rs | 42 +- src/common/rust/src/cancelatom.rs | 98 + src/common/rust/src/filefunctions.rs | 13 + src/common/rust/src/handle.rs | 40 +- src/common/rust/src/lib.rs | 1 + src/common/rust/tests/ffi_colortransform.rs | 6 +- src/engine/rust/Cargo.lock | 4 + src/engine/rust/src/audio.rs | 7 +- src/engine/rust/src/bridge/audio.rs | 447 +-- src/engine/rust/src/bridge/codec.rs | 232 +- src/engine/rust/src/bridge/common.rs | 889 ++++-- src/engine/rust/src/bridge/node.rs | 2887 ++++++++++++++----- src/engine/rust/src/bridge/plugin.rs | 68 +- src/engine/rust/src/bridge/render.rs | 411 ++- src/engine/rust/src/bridge/task.rs | 307 +- src/engine/rust/src/bridge/timeline.rs | 368 ++- src/engine/rust/src/bridge/undo.rs | 230 +- src/engine/rust/src/handle.rs | 64 +- src/engine/rust/src/node.rs | 25 +- src/engine/rust/src/timeline.rs | 2 +- src/engine/rust/tests/node.rs | 6 +- src/node/rust/Cargo.lock | 334 +++ src/node/rust/Cargo.toml | 2 + src/node/rust/src/bridge/undo.rs | 89 +- src/node/rust/src/colormanager.rs | 38 +- src/node/rust/src/handle.rs | 45 +- src/node/rust/src/project.rs | 8 +- src/oakcore-rs/src/handle.rs | 95 + src/oakcore-rs/src/lib.rs | 4 + src/plugin/rust/Cargo.lock | 5 + src/plugin/rust/Cargo.toml | 2 + src/plugin/rust/src/handle.rs | 44 +- src/render/rust/Cargo.lock | 150 + src/render/rust/Cargo.toml | 1 + src/render/rust/src/cancelatom.rs | 82 +- src/render/rust/src/ffi.rs | 9 +- src/render/rust/src/handle.rs | 42 +- src/render/rust/src/manager.rs | 5 +- src/task/rust/Cargo.lock | 135 + src/task/rust/src/handle.rs | 47 +- src/task/rust/tests/bridge_test.rs | 23 +- src/timeline/rust/src/handle.rs | 37 +- src/undo/rust/src/ffi.rs | 79 +- src/undo/rust/src/handle.rs | 36 +- src/undo/rust/tests/ffi_contract_test.rs | 5 +- 49 files changed, 5636 insertions(+), 2282 deletions(-) create mode 100644 docs/zh/plans/riir/single-lib.md create mode 100644 src/common/rust/src/cancelatom.rs create mode 100644 src/oakcore-rs/src/handle.rs diff --git a/docs/zh/plans/riir/single-lib.md b/docs/zh/plans/riir/single-lib.md new file mode 100644 index 000000000..02d15cff2 --- /dev/null +++ b/docs/zh/plans/riir/single-lib.md @@ -0,0 +1,400 @@ +# 单库化(single-lib)· 模块间调用改回直接 Rust 调用 + +> 2026-08-10。本计划是 RIIR 拆分计划的**反向修正**:模块拆分阶段为了 +> 让各 crate 独立链接,把模块间调用压成了 C ABI(`bridge/` + dlsym / +> link-time extern)。现在模块已经全部 Rust 化,owner 要求模块间调用 +> **改回直接 Rust 调用**(一个 `liboakengine` dylib 内联全部模块; +> unsafe 只允许留在 OFX 插件边界、引擎对外 C API、以及 shm/wgpu/libc +> 等不可避免的位置)。 +> +> 约束(本次任务硬性要求): +> 1. **不改变** `oakengine_*` 外部签名与各模块 C ABI 签名 +> (`app`/`worker`/`cli` 继续工作;`src/plugin` 的 C-ABI 冻结)。 +> 2. **不触碰** OFX 插件边界(oakplugin 的 suites 保持 C)。 +> 3. 每个 crate 的 `cargo test`、`src/engine/rust` 的 `cargo test` +> 全程保持绿(每步闭环)。 +> 4. Oak GPL 头、tab 缩进、不做 git 变更。 + +## 0. 目标与判据 + +终态: + +``` +liboakengine(一个 dylib,crate 图是 DAG) +├── oakcore-rs ← 共享 ABI 类型(CHandle + POD),无依赖的叶子 +├── oakcommon → oakcore-rs +├── oakundo → oakcore-rs +├── oaknode → oakcore-rs, oakcommon, oakundo, oakcodec +├── oaktimeline → oakcore-rs, oakundo, oaknode +├── oakcodec → oakcore-rs, oakrender (codec→render 直接调) +├── oakaudio → oakcore-rs, oakcommon, oakcodec +├── oakrender → oakcore-rs, oakcommon, oaknode (render→node 直接调) +├── oaktask → oakcore-rs, oakcommon, oakundo, oakcodec, oaknode, oakrender +├── oakplugin → oakcore-rs, oakcommon, oakundo, oaknode, oakrender(suites 仍 C) +└── oakengine → 全部(facade) +``` + +完成判据(每条命令可验证): + +1. 模块间、facade→模块的调用 **100% 是编译期 Rust 函数调用**: + `grep -rn "extern \"C\"" --include="*.rs" src/{undo,common,timeline,codec,audio,render,task,plugin,node}/rust/src/bridge/` = 0; + `grep -rn "dlsym" --include="*.rs"` 只剩 facade 的 `linkage.rs`/`tests/` 注释与 + OFX host(oakplugin suites)里的必要解析。 +2. 模块 C ABI(`oakundo_*` … `oaknode_*`)与 `oakengine_*` 依旧从 + `liboakengine` dylib 导出(`nm -g liboakengine.dylib` 抽查)—— + 外部的 `oaknode_project_init` 等签名一行不改。 +3. 每个 crate `cargo build` 0 error;每个 crate `cargo test` 绿; + `src/engine/rust` `cargo test` 绿。 +4. unsafe 面收敛:模块 src 中,除 + `{ffmpeg, ocio, wgpu, libc, shm} → unsafe` 包裹与各自 `ffi.rs` 导出外, + 无残留;`bridge/` 目录从模块 crate 中消失(或只余测试桩,见 §7)。 + +## 1. 现状盘点(2026-08-10 实测) + +### 1.1 crate 依赖现状 + +模块 crate 之间**没有 path 依赖**;跨模块调用走各自的 `bridge/`: + +| crate | 跨界机制 | bridge/ 规模(行) | dlsym::call 数 | +|---|---|---|---| +| oaknode | dlsym(RTLD_DEFAULT) | codec 1270 / common 50340 / core 5298 / render 5134 / timeline 2161 / undo 12964 | 59 | +| oakrender | dlsym | codec 6904 / common 7419 / node 5750 | 20 | +| oakplugin | dlsym | node 12124 / render 30454 / undo 10943 | 28 | +| oaktask | extern "C"(link-time) | codec 9909 / common 5980 / node 26044 / render 12340 / timeline 1291 / undo 2528 | 0 | +| oakcodec | extern "C" | common 15657 / render 7262(+test_stubs 27176) | 0 | +| oakaudio | extern "C" | codec 6683 / common 1665 / ffmpeg 7812 | 0 | +| oaktimeline | extern "C" | common / node 11742 / undo 2780(+teststubs 52921) | 0 | +| oakundo / oakcommon | — | 无 bridge | — | + +facade `src/engine/rust/src/bridge/`:9 个文件 2466 行、**624 个 +`extern "C"` 导入**(node 348 / common 91 / render 36 / timeline 34 / +task 33 / audio 31 / codec 24 / undo 22 / plugin 5),由 +`linkage.rs` 锚定 13 个 `#[no_mangle]` 符号把模块 rlib 拉进 dylib。 + +### 1.2 真实调用方向(生产代码,不含 bridge 定义与测试桩) + +按 "`crate::bridge::` 在 `` 生产代码中的出现" 统计(类型别名引用 +与文档注释已剔除,函数调用计数): + +| 方向 | 生产调用 | 说明 | +|---|---|---| +| node → render | **3** | `disk_cache_path`(project.rs)、`color_config_create_default`/`color_config_load`(colormanager.rs);其余是 `TextureHandle`/`ColorProcessorHandle`/`CacheHandle` 等**不透明 CHandle 类型别名** | +| render → node | **6** | `copier.rs`:`project_deep_copy` / `project_sync_copy` / `ChangeRecord` / `node_abi_available` | +| node → codec | 1 | — | +| node → timeline | **0** | bridge 是死代码(仅测试用) | +| timeline → node | 7 | — | +| node → undo | 15 | — | +| node → common | 21 | — | +| codec → render | 8 | cancelatom(`heard_cancel` 生产、`init`/`cancel` 测试)+ `OakCancelAtom`/`OakRenderTexture` 类型 | +| render → codec | **1** | `ffi.rs:931` 的 `codec_abi_available()`,位于必然 Err 的 deferred stub 路径 | +| task → node/render/codec | 1 / 6 / 3 | timeline / undo 为 0 | +| plugin → node/render/undo | 14 / 38 / 13 | suites 层保持 C(冻结) | +| audio → codec/common | 12 / 4 | — | +| timeline → undo | 5 | — | +| **facade → 各模块** | **393 处调用** | 见 §5 | + +### 1.3 环(Rust crate 禁止循环 path 依赖) + +| 环 | 边 | 处理 | +|---|---|---| +| **node ↔ render** | node→render 3 fn + render→node copier | §4.1:render→node 保留直接依赖;node→render 的 3 个函数下沉 oakcommon(实现本就在 oakcommon 侧:`default_disk_cache_path` 已是 render/bridge/common.rs 内的纯 Rust 实现;OCIO config 由 oakcommon `ocioutils::OcioConfig` 提供) | +| **codec ↔ render** | codec→render cancelatom + render→codec stub | §4.2:cancelatom 下沉 oakcommon(原子取消旗标,纯 Rust);render→codec 的 stub 检查直接删除(路径必然 Err) | + +其余方向均无环:node→timeline 0 调用、task→* 单向、plugin→* 单向、 +audio→* 单向、timeline→node/undo 单向。 + +## 2. 目标架构:直接 Rust 调用 + 单一 dylib + +### 2.1 公共面分层(每个模块 crate) + +每个模块 crate 的公共面分两层,对应"机械落地"与"类型化"两档: + +- **Layer 1(本次任务落地):`ffi` 即公共面,调用方直接 Rust 调用。** + 模块 C ABI 函数是 `pub unsafe extern "C" fn`(`#[no_mangle]` 保持导出)。 + 引擎内部调用不再走 `extern "C"` 导入、不走 dlsym,而是 + `oaknode::ffi::project::oaknode_project_init()` 这样的**普通 Rust + 函数调用**——编译期类型检查、链接期直接解析到同 dylib 内的 rlib。 + 调用方在**包装层**(各 crate 的 bridge 改为安全包装 fn)一次性 + `unsafe {}` 包住,业务代码保持 safe。 +- **Layer 2(增量、后续):类型化 API。** 各 crate 已有的非 ffi 模块 + (`project::Project`、`undostack::UndoStack`、`graph::Graph`、 + `marker::Marker`、`manager::Manager`…)即"types, not CHandle"方向; + 目前只覆盖部分操作,其余操作仍实现于 `ffi.rs`(CHandle 上)。新代码 + 优先写类型层;把 `ffi.rs` 里的逻辑逐步提取成类型方法属于后续增量, + **不在本任务范围内**(本任务只改调用机制,不改实现)。 + +### 2.2 类型同一性:共享 ABI 类型下沉 oakcore-rs(本任务的地基) + +直接 Rust 调用要求调用方与被调方**类型同一**。现状是每个 crate 各有一份 +layout 相同但 Rust 类型不同的 `CHandle`、POD(`OakVideoParams`、 +`OakAudioParams`、`OakRational`、`OakNodeValue`…)。必须统一: + +- `oakcore-rs` 新增(或接收): + - `handle::CHandle`(`{ctx, addref, release, abi_version}`,`#[repr(C)]`, + 含 `null()`/`is_null()`,`Send + Sync`;`abi_version` 不校验, + 只作标签——统一后 `null()` 盖 0,各 crate 的 `make_owned` 仍盖各自 + 的 `OAKXXX_ABI_VERSION`); + - 跨界 POD:`params::OakVideoParams`、`params::OakAudioParams`、 + `rational::Rational`(已有)、`value::OakNodeValue` 等。 +- 各模块 crate:`pub use oakcore_rs::handle::CHandle;`(`handle.rs` 保留 + `RefBox`/`make_owned`/`guard*`/ABI 版本常量);POD 同理 re-export。 + 各 crate 的 `ffi.rs` **签名不改**(类型名不变,只是指向共享类型, + C ABI 层面 layout 不变)。 +- facade:`pub use oakcore_rs::handle::CHandle;`,`OakVideoParamsPod` 等 + 改为 `pub type OakVideoParamsPod = oakcore_rs::params::OakVideoParams;`。 + +> 这是"机械"的底气:统一后 `oaknode::ffi::project::oaknode_project_init()` +> 的返回类型就是 facade `OakEngineProject.handle` 的类型,调用点 +> **一行不用改**。§7 会说明 facade `bridge/` 保留同名安全包装,因此 +> facade 21k 行业务代码零改动。 + +## 3. 每 crate 的 bridge/ 去向 + +原则:**生产代码不再经过任何 `bridge/`;bridge/ 从生产路径删除。** + +| crate | 处理 | +|---|---| +| facade `engine/rust/src/bridge/` | §5:`extern "C"` 块 → 直接调用模块 crate `ffi` 的安全包装(同名同签名) | +| oaknode `bridge/{undo,common,codec}` | 直接调用 oakundo/oakcommon/oakcodec 的 ffi;`bridge/` 删除 | +| oaknode `bridge/{render,timeline,core}` | render/timeline 见 §4(环/死代码);core → oakcore-rs / 宿主 liboakcore(保持 link-time extern,见 §4.3) | +| oaktask `bridge/*` | 直接调用各目标 crate ffi;`bridge/` 删除 | +| oakrender `bridge/node` | 直接调用 oaknode ffi(§4.1) | +| oakrender `bridge/{codec,common}` | codec → §4.2(stub 删除);common → 直接调用 oakcommon | +| oakplugin `bridge/{node,render,undo}` | 直接调用各目标 crate ffi;suites 保持 C | +| oakcodec `bridge/{common,render}` | common → oakcommon;render → oakrender(cancelatom 移 oakcommon 后改调 oakcommon,见 §4.2) | +| oakaudio `bridge/{codec,common,ffmpeg}` | codec/common → 直接调用;ffmpeg → ffmpeg_bridge(C++,保持 extern "C") | +| oaktimeline `bridge/{node,undo,common}` | node/undo → 直接调用;common 0 调用 → 删除;`teststubs.rs` 见 §7 | + +**同名 `#[no_mangle]` 冲突**:两个 crate 导出同名 `#[no_mangle]` 符号 +在单个 dylib 里本来就不允许(重复符号)。现状不会冲突(每个 C ABI 符号 +唯一归属一个 crate)。内部调用改成直接 Rust 调用后,**外部 C ABI 符号 +原样保留**(`oaknode_*` 仍由 oaknode crate 导出,供 `app`/`worker`/ +`cli` 与各 crate 的 C ABI 测试使用);内部调用**绕过**这些符号,走 +`pub` Rust fn。任何"同符号双实现"都不引入——机制上天然避免。 + +## 4. 依赖环处理 + +### 4.1 node ↔ render(实施结论:两侧调用均为死代码,删除即破环) + +实施时发现:**两侧的跨模块调用都是死代码**——`oaknode` 的 dlsym 目标 +(`oakrender_color_config_*`)与 `oakrender` 的 dlsym 目标 +(`oaknode_project_deep_copy`/`project_sync_copy`)**在对方 crate 中从未 +实现**(2026-08-10 全量 grep 确认),所以运行时必然 dlsym 失败,走 +"缺失"分支。破环 = 删除死调用: + +1. `disk_cache_path()`:实现**下沉 oakcommon**(新增 + `filefunctions::default_disk_cache_path()`,基于既有的 + `FileFunctions::get_configuration_location()`)。oaknode + `project.rs` 与 oakrender `manager.rs` 都直接调 oakcommon。 +2. `color_config_create_default()`/`color_config_load()`:oakrender 从未 + 实现这两个符号 → node `colormanager.rs` 的调用恒为 `None`(走 + "标记已加载/保持原状" 分支)。删除调用、保留确定性等价逻辑(行为不变)。 +3. render 的 `copier.rs`(`project_deep_copy` 等)同样恒失败且无生产 + 调用方——保持现状(dlsym 运行时失败),不引入 crate 依赖。 + +**类型别名**:node 里存的 `TextureHandle`/`ColorProcessorHandle`/ +`CacheHandle` 本就是 `pub type X = CHandle`(统一后 = +`oakcore_rs::handle::CHandle`),零依赖。 + +结果:node 与 render 之间无任何 crate 依赖、无任何有效调用,环消失。 + +### 4.2 codec ↔ render(实施结论:cancelatom 保持 C 边界,render 的 stub 删除) + +- **render → codec**:`ffi.rs:931` 的 `codec_abi_available()` 位于 + deferred stub(`Err(...)` 恒返回),**已删除**(保留原 Err 文案)。 + render→codec = 0。 +- **codec → render**:只有 cancelatom。实施时发现 codec 收到的 atom 句柄 + 是 oakrender `make_owned` 按 **oakrender 的 `RefBox` 布局**装箱的, + codec 直接解引用会在不同 crate 的 `RefBox` 布局间读内存(oakcommon + value-first、其余 refs-first),**不安全**。因此 cancelatom 的读取保持 + 经 oakrender 的 C 导出(codec `bridge::render` 的 link-time extern, + 与 `oakcore_*`/`fb_*` 同类,属"不可避免的 C 边界");实现体下沉 + oakcommon(`cancelatom::CancelAtom`,oakrender 的 + `oakrender_cancelatom_*` 导出改包 oakcommon,`render/cancelatom.rs` + 变为 re-export)。 + +结果:codec 与 render 之间无 crate 依赖;codec→render 仅剩 cancelatom +一个 link-time C 边界。 + +### 4.3 oakcore_*(宿主 liboakcore)与 fb_*(ffmpeg_bridge) + +`oakcore_audioparams_*` / `oakcore_rational_*`(宿主 C++ liboakcore)与 +`fb_*`(ffmpeg_bridge C++)**不是 Rust crate**,无法变成直接 Rust 调用: +保持现状(dylib 链接期 runtime lookup,`build.rs` 的 +`-Wl,-undefined,dynamic_lookup`)。`bridge/core.rs` 之类保留为 link-time +extern(或就地声明),属于"不可避免的 C 边界"。 + +## 5. facade bridge → 直接调用(步骤 a,最大但机械) + +`src/engine/rust/src/bridge/*.rs` 从 `extern "C" { ... }` 导入改为 +**同名同签名的安全包装 fn**: + +```rust +// src/bridge/node.rs(改写后) +use oakcore_rs::handle::CHandle; +/// `oaknode_project_init` — 直接调用 oaknode crate(同 dylib 内 rlib)。 +pub fn oaknode_project_init() -> CHandle { + unsafe { oaknode::ffi::project::oaknode_project_init() } +} +``` + +- 每个 ffi fn 的路径:`oak::ffi::<子模块>::`(如 + `oaknode::ffi::project`、`oaknode::ffi::folder`、`oakcommon::ffi::config`…); + 实现时以模块 crate 实际 `pub mod` 布局为准(已核对:oaknode ffi 有 + `project/node/keyframe/…` 子模块)。 +- **facade 业务代码(node.rs/timeline.rs/… 共 393 处调用)零改动**: + 它们只 `use crate::bridge::node as n;` 然后 `n::oaknode_project_init()`, + 包装 fn 同名同签名,链接目标从"extern 导入"变成"直接调用"。 +- unsafe 收口在包装层:模块 ffi 是 `pub unsafe extern "C" fn`,包装层 + 一处 `unsafe {}`。facade 其余代码保持 safe(现存的散落 `unsafe {}` + 调用点一并消除)。 +- `linkage.rs` 保留(锚定符号导出,供外部 C ABI),注释更新。 +- 现 facade 里 `crate::bridge::common` 的 POD 镜像(`OakVideoParamsPod`) + 改为 `type` 别名共享类型(§2.2)。 + +## 6. 模块 bridge → 直接调用(步骤 b) + +逐方向(每步一个 crate 一个方向,`cargo build`+`cargo test` 闭环): + +1. oaknode:`bridge/undo.rs`、`bridge/common.rs`、`bridge/codec.rs` + (→ oakundo/oakcommon/oakcodec 直接调,同 §5 的包装写法); +2. oaktimeline:`bridge/node.rs`、`bridge/undo.rs`(→ oaknode/oakundo); +3. oakrender:`bridge/node.rs`(→ oaknode,§4.1)、`bridge/common.rs` + (→ oakcommon); +4. oaktask:`bridge/{node,render,codec,undo,common}.rs`; +5. oakplugin:`bridge/{node,render,undo}.rs`(suites 不动); +6. oakcodec:`bridge/common.rs`(→ oakcommon)、`bridge/render.rs` + (→ oakcommon cancelatom,§4.2); +7. oakaudio:`bridge/{codec,common}.rs`; +8. oaknode:`bridge/render.rs`(→ oakcommon,§4.1)、`bridge/timeline.rs` + (死代码删除,测试迁移见 §7)、`bridge/core.rs`(§4.3 保留 extern)。 + +被调方需要被加为 path 依赖的 crate:oaknode 加 `oakundo`/`oakcommon`/ +`oakcodec`;oaktimeline 加 `oakundo`/`oaknode`;oakrender 加 +`oakcommon`/`oaknode`;oaktask 加 `oakundo`/`oakcommon`/`oakcodec`/ +`oaknode`/`oakrender`;oakplugin 加 `oakcore-rs`/`oakcommon`/`oakundo`/ +`oaknode`/`oakrender`;oakcodec 加 `oakcommon`;oakaudio 加 +`oakcommon`/`oakcodec`。**不产生任何环**(§1.3 已消除)。 + +## 7. 测试策略(每 crate 测试保持绿) + +- **每 crate 测试沿用 C ABI 测试为主**(`tests/*.rs` 走 crate 自己的 + `oak_*` 导出,`ffi.rs` 不变),**内部 Rust API 测试增量补充**。 +- **用 `bridge/` 的测试必须迁移**(桥层从生产路径删除后不能留在测试里): + - 目标 crate 已 path 依赖的:`oaknode::bridge::undo::…` → + `oakundo::ffi::…`(或 oakundo 类型层)直接调;`bridge::common::videoparams_*` + → `oakcommon::…`;`bridge::core::audioparams_*` → `oakcore_rs::…` + / 宿主 liboakcore extern; + - 依赖不存在(环/死代码)的:`node::bridge::timeline` 的测试用 + oaktimeline 自身导出或改写;`node::bridge::render` 的测试改调 + oakcommon 下沉后的函数; + - 专门测 dlsym 机制的测试(如 `node/rust/tests/dbg2_test.rs` 的 + `bridge::dlsym::resolve`)随机制删除而删除。 +- **`test-stubs` feature(oakplugin/oakcommon/oaktimeline/oaknode)**: + 语义变为"编译测试桩 C ABI(替代尚未存在的宿主/兄弟模块实现)"。 + 直接调用落地后,同一二进制内不再同时出现"真实现 + 桩"冲突: + facade `cargo test` 的 dev-dependency feature union 按新依赖图调整 + (凡直接依赖的 crate 用真实现,不再叠 test-stubs)。 +- facade `tests/`(10 个集成测试)走 `oakengine_*` C ABI,不受影响; + `tests/common/mod.rs` 的 `force_link` 更新锚点。 + +## 8. unsafe 清单(before / after) + +| 位置 | 现状(实测计数) | 之后 | +|---|---|---| +| 模块 `bridge/`(dlsym + extern 包装) | node 298 / plugin 167 / timeline 137 / render 45 / codec 50 / task 15 处 `unsafe` 行 | **删除**(或仅测试桩) | +| 模块 `ffi.rs` 导出(`unsafe extern "C"`,内含句柄解包) | 各 crate 均有 | **保留**(= 模块 C ABI,外部契约;内部调用在包装层包 unsafe) | +| 模块业务代码中散落的 `unsafe` | node ~1020 / plugin ~476 / codec ~533 / render ~277 / task ~306 / timeline ~271 / audio ~165 / common ~230 / undo ~80 行 | 只保留**包裹外部库**(ffmpeg/ocio/wgpu/libc)的调用与必要的句柄解包;bridge 调用产生的 unsafe 随桥层消失 | +| oakplugin suites(OFX host) | C 套件 trampoline | **保持 C**(冻结,任务红线) | +| facade `engine/rust/src` | 1642 行 `unsafe`(含 ipc/shm 1120+ 行、worker、handle guard、桥层 10 行) | 桥层包装 unsafe 保留;`handle.rs` guard/unbox、`ipc.rs` shm、`worker.rs` 保留(外部 C API 与 shm,属允许项) | +| `linkage.rs` / `build.rs` | — | 保留(符号锚定 + `-Wl,-undefined,dynamic_lookup`,宿主 C++ 符号必需) | + +判定:模块 crate 中"非外部库包裹"的 unsafe 清零;facade 中 unsafe 只留 +{导出 guard、shm/ipc、worker 会话}。 + +## 9. 实施顺序(一次一个边界,每步构建+测试闭环) + +1. **地基**:`oakcore-rs` 新增 `handle::CHandle`;各 crate + `handle.rs` 改 re-export;facade 改 re-export。逐 crate 验证 + `cargo build` + `cargo test`(这一步后直接调用才类型同一)。 +2. **facade bridge → 直接调用**(§5,步骤 a)。 +3. **环处理**(§4):删除死调用;disk_cache_path/cancelatom 下沉 + oakcommon;render 的 `codec_abi_available()` stub 检查删除。 +4. **模块 bridge 逐方向 → 直接调用**(§6,步骤 b)。 +5. **dlsym 删除**(步骤 c):node/render/plugin 的 `bridge/mod.rs::dlsym` + 与残留调用清除;`linkage.rs` 注释更新。 +6. **测试迁移**(§7)与全量验证:每 crate `cargo test` + + `src/engine/rust` `cargo test` + 抽查 dylib 导出。 + +## 11. 实施状态(2026-08-10 实测) + +已落地(全部构建 0 error、全量 `cargo test` 绿): + +- **地基**:`oakcore_rs::handle::CHandle`(`Clone+Copy+Debug+Default`, + `Send+Sync`,`null()` 盖 0)。10 个 crate + facade 全部 re-export; + 各 crate 的 `impl CHandle`、`unsafe impl Send/Sync` 删除。受影响断言 + (common/codec/audio/task 的 null-handle 版本/函数指针测试)已同步更新。 +- **facade bridge**(步骤 a):9 个文件 624 个 `extern "C"` 导入中 + **618 个改为直接 Rust 调用**(`unsafe { oak::ffi::::(...) }` + 安全包装,名字签名不变,facade 业务代码 393 处调用点零改动)。 + 保留 8 个 link-time extern:`oakcore_audioparams_*` ×5(宿主 C++)、 + `oakaudio_manager_start_recording`/`oakcodec_encoder_init`/ + `oaktask_create_export`(encoding-params C ABI POD,facade 保留自己的 + POD 镜像,见 §11.1)。 +- **签名漂移修复**(直接调用把 facade 旧 extern 声明与模块真实签名之间的 + 漂移暴露为编译错误):`videoparams_init_basic` 4→8 参、 + `init_with_time_base` 4→10 参、`get_bytes_per_channel_for_format` + 2→1 参、`oakaudio_manager_seconds` 1→2 参、 + `oakaudio_sync_estimate_stretch_and_offset` 9→12 参(facade 导出现在 + 把引擎的 `min_rate/max_rate/rate_step` 透传给模块,消除了原先 + "模块自搜默认范围"的 documented deviation)、`get_buffer_size`/ + `get_time_in_timebase_units`/`get_bytes_per_pixel_for_format` 参数 + 类型修正。POD 统一:`OakNodeValue`→`oaknode::value::OakNodeValue` + (`type_` 字段改名 `kind`,1 读 3 构 + 1 测试更新)、 + `OakUndoCommandVtable`/`OakVideoTicketParams`/`OakRenderVideoParams`/ + `OffsetResult`/`StretchOffsetResult`/`SourceClip` → 各模块 crate 类型。 +- **环处理**(§4 实施结论):node↔render 死调用删除;render→codec stub + 删除;`oakcommon::{filefunctions::default_disk_cache_path, cancelatom}`; + render 的 `cancelatom.rs` 改为 re-export。 +- **模块 bridge**(步骤 b,模式已证明):oaknode `bridge/undo.rs` + → oakundo 直接调用(oakundo 加入 node 依赖;bridge 函数名/签名不变, + node 生产代码与测试零改动,全部绿)。 + +### 11.1 保留的 C 边界(facade bridge 中 8 个 extern 声明) + +encoding-params POD(`oakcodec_encoding_params` 等)在 4 个 crate 各有 +镜像(codec/audio/task/facade),字段仅 `[c_char;N]` vs `[u8;N]` 差异, +统一到 oakcore-rs 属后续增量(§5 已注明);在此之前,跨越该 POD 的 3 个 +函数与宿主 `oakcore_*` 保持 link-time extern,与 `fb_*` 同类。 + +### 11.2 未完成(后续步骤) + +- **模块 bridge 其余方向**(步骤 b 剩余):oaknode `bridge/{common,codec, + core,render,timeline}`、oaktimeline `bridge/{node,undo,common}`、 + oakcodec `bridge/{common,render}`、oakaudio `bridge/{codec,common,ffmpeg}`、 + oakrender `bridge/{codec,common,node}`、oaktask `bridge/*`、 + oakplugin `bridge/*`。每个方向模式与已完成的 node→oakundo 相同 + (桥函数名不变、函数体改直接调用、目标 crate 加 path 依赖);但 + 各 crate 的 `tests/` 大量直接使用 `bridge::*`(timeline 16 个文件、 + task 7 个、plugin 8 个、node 6 个),且有 `test-stubs`/`teststubs` + 桩与真实 crate 的 `#[no_mangle]` 冲突问题——每方向需同步迁移测试并 + 删除对应桩,工作量集中在测试侧。 +- **dlsym 删除**(步骤 c):node/render/plugin 的 `bridge/mod.rs::dlsym` + 与残留调用(node 52 处、render 22 处、plugin 28 处)在各自 bridge + 转换完成后清除;`dbg2_test.rs` 等专测 dlsym 的测试随之删除。 +- **facade 侧后续**:`linkage.rs` 的 13 个锚定符号注释更新(锚定仍需要); + EncodingParamsPOD 等 POD 统一到 oakcore-rs。 + +## 10. 风险与回退 + +- **共享类型统一**是全局改动:改完一个 crate 编译它,逐 crate 推进; + 若某 crate 的 `CHandle` 有独有 impl 方法,移入共享 impl 或改为扩展 fn。 + `abi_version` 统一为 0 标签后,逐 crate 测试确认无断言依赖。 +- **模块 ffi fn 路径**(`oaknode::ffi::project` 等)以实际 `pub mod` + 布局为准;包装层用编译错误驱动修正路径。 +- **宿主符号**(`oakcore_*`/`fb_*`)与 `build.rs` 的 + `-Wl,-undefined,dynamic_lookup` 不动;这些不是 Rust crate,是允许保留 + 的 C 边界。 +- **行为零变更**:本计划只改调用机制(extern/dlsym → Rust fn),不改 + 实现;任何"顺带重构"禁止。回退 = 保留 `bridge/` 目录(生产已不引用), + 不影响外部契约。 diff --git a/src/audio/rust/src/handle.rs b/src/audio/rust/src/handle.rs index c230dc8a8..8ebe47b52 100644 --- a/src/audio/rust/src/handle.rs +++ b/src/audio/rust/src/handle.rs @@ -54,47 +54,13 @@ pub struct RefBox { pub value: T, } -/// `#[repr(C)]` mirror of the public handle structs -/// (`{ctx, addref, release, abi_version}`). -/// -/// Handles cross the C ABI by value (the C caller copies the 4-field -/// struct), so the type is `Copy`/`Clone` — the oaknode crate only derives -/// `Clone`, but `Copy` matches the C semantics exactly and lets exports and -/// tests pass the same handle around freely. No `Drop`: releasing goes -/// through the explicit `free_*`/`release` path, never on scope exit. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -// Handles are passed by value across the C ABI and used from the caller's -// thread; the objects behind them synchronize their own state. -unsafe impl Send for CHandle {} - -impl CHandle { - /// The empty handle. - pub fn null() -> Self { - CHandle { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: OAKAUDIO_ABI_VERSION, - } - } - - /// True when the handle carries no object. - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. It is `Clone + Copy` (handles cross the C ABI by +/// value) and `Send + Sync` (refcounted, shared across threads). +pub use oakcore_rs::handle::CHandle; /// `// CPP-PARITY: src/audio/c_api/refcounted.h` (`ref_counted_addref`). unsafe extern "C" fn owned_addref(ctx: *mut std::ffi::c_void) { diff --git a/src/audio/rust/tests/ffi_test.rs b/src/audio/rust/tests/ffi_test.rs index 64e6cb961..037f12b57 100644 --- a/src/audio/rust/tests/ffi_test.rs +++ b/src/audio/rust/tests/ffi_test.rs @@ -93,7 +93,8 @@ fn manager_singleton_and_alive_count() { unsafe { oakaudio_manager_destroy_instance() }; let none = unsafe { oakaudio_manager_instance() }; assert!(none.ctx.is_null()); - assert_eq!(none.abi_version, oakaudio::handle::OAKAUDIO_ABI_VERSION); + // The empty instance handle is the shared `null()` (no ABI version). + assert_eq!(none.abi_version, 0); unsafe { oakaudio_manager_create_instance() }; let m1 = unsafe { oakaudio_manager_instance() }; diff --git a/src/audio/rust/tests/handle_test.rs b/src/audio/rust/tests/handle_test.rs index 99dc250c6..4bdeda0af 100644 --- a/src/audio/rust/tests/handle_test.rs +++ b/src/audio/rust/tests/handle_test.rs @@ -79,7 +79,8 @@ fn borrowed_release() { fn null_and_guard_ok() { let null = CHandle::null(); assert!(null.is_null()); - assert_eq!(null.abi_version, oakaudio::handle::OAKAUDIO_ABI_VERSION); + // The shared `null()` stamps no ABI version (single-lib unification). + assert_eq!(null.abi_version, 0); assert_eq!(guard(|| Ok(())), OAKAUDIO_OK); diff --git a/src/codec/rust/src/handle.rs b/src/codec/rust/src/handle.rs index ddaf572e8..d675e6c87 100644 --- a/src/codec/rust/src/handle.rs +++ b/src/codec/rust/src/handle.rs @@ -46,38 +46,12 @@ pub struct RefBox { /// `#[repr(C)]` mirror of the public handle structs /// (`{ctx, addref, release, abi_version}`). -/// -/// Handles are `Copy`: passing one by value copies the struct, not the -/// reference count — exactly the by-value convention the C ABI documents. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[repr(C)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -impl CHandle { - /// The empty handle. - pub fn null() -> Self { - CHandle { - ctx: ptr::null_mut(), - addref: None, - release: None, - abi_version: OAKCODEC_ABI_VERSION, - } - } - - /// Whether this is an empty (null) handle. - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. +pub use oakcore_rs::handle::CHandle; /// Increment the reference count of a boxed `RefBox`. /// @@ -293,6 +267,8 @@ mod tests { fn null_handle_helpers() { let h = CHandle::null(); assert!(h.is_null()); - assert_eq!(h.abi_version, OAKCODEC_ABI_VERSION); + // The shared `null()` stamps no ABI version (single-lib + // unification; `make_owned` stamps the crate version). + assert_eq!(h.abi_version, 0); } } diff --git a/src/common/rust/src/cancelatom.rs b/src/common/rust/src/cancelatom.rs new file mode 100644 index 000000000..b07ea28bb --- /dev/null +++ b/src/common/rust/src/cancelatom.rs @@ -0,0 +1,98 @@ +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! The cancellation primitive (`olive::CancelAtom`): a thread-safe cancel +//! flag shared between a render/encode caller and its worker. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): moved +//! here from the oakrender crate so the oakcodec crate can use it without +//! depending on oakrender (the oaknode/oakcodec/oakrender call cycle). + +use std::sync::{Mutex, MutexGuard}; + +/// A cancellation atom (C++ `CancelAtom`). Reading a set flag also records +/// that a consumer heard the cancellation. +#[derive(Default)] +pub struct CancelAtom { + state: Mutex, +} + +#[derive(Default)] +struct AtomState { + cancelled: bool, + heard: bool, +} + +fn lock(m: &Mutex) -> MutexGuard<'_, AtomState> { + m.lock().unwrap_or_else(|e| e.into_inner()) +} + +impl CancelAtom { + /// A not-cancelled atom. + pub fn new() -> Self { + Self::default() + } + + /// Set the cancel flag (C++ `CancelAtom::cancel()`). + pub fn cancel(&self) { + lock(&self.state).cancelled = true; + } + + /// Read the cancel flag; reading a set flag records that the + /// cancellation was heard (C++ `is_cancelled()`). + pub fn is_cancelled(&self) -> bool { + let mut s = lock(&self.state); + if s.cancelled { + s.heard = true; + } + s.cancelled + } + + /// Whether any consumer has observed the cancel flag through + /// [`CancelAtom::is_cancelled`] (C++ `heard_cancel()`). + pub fn heard_cancel(&self) -> bool { + lock(&self.state).heard + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fresh_atom_is_not_cancelled() { + let a = CancelAtom::new(); + assert!(!a.is_cancelled()); + assert!(!a.heard_cancel()); + } + + #[test] + fn cancel_sets_flag_and_reading_marks_heard() { + let a = CancelAtom::new(); + a.cancel(); + assert!(!a.heard_cancel(), "not heard until read"); + assert!(a.is_cancelled()); + assert!(a.heard_cancel(), "reading a set flag marks it heard"); + } + + #[test] + fn repeated_cancel_is_idempotent() { + let a = CancelAtom::new(); + a.cancel(); + a.cancel(); + assert!(a.is_cancelled()); + } +} diff --git a/src/common/rust/src/filefunctions.rs b/src/common/rust/src/filefunctions.rs index b974e6715..3bbfbc211 100644 --- a/src/common/rust/src/filefunctions.rs +++ b/src/common/rust/src/filefunctions.rs @@ -920,3 +920,16 @@ mod tests { let _ = std::fs::remove_dir_all(&b); } } + +/// The default disk cache directory (C++ `DiskManager:: +/// get_default_disk_cache_path`): `/mediacache`. +/// +/// Single-lib unification: this used to live in the oakrender crate's +/// `bridge::common` fallback (see `docs/zh/plans/riir/single-lib.md`); +/// oaknode and oakrender both call it directly now. +pub fn default_disk_cache_path() -> String { + Path::new(&FileFunctions::new().get_configuration_location().unwrap_or_default()) + .join("mediacache") + .to_string_lossy() + .into_owned() +} diff --git a/src/common/rust/src/handle.rs b/src/common/rust/src/handle.rs index 9dc1b50b9..b6e6e9613 100644 --- a/src/common/rust/src/handle.rs +++ b/src/common/rust/src/handle.rs @@ -59,36 +59,12 @@ pub struct RefBox { pub refs: AtomicU32, } -/// `#[repr(C)]` mirror of the public handle structs -/// (`{ctx, addref, release, abi_version}`). -#[repr(C)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -impl CHandle { - /// The empty handle. - pub fn null() -> Self { - Self { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: OAKCOMMON_ABI_VERSION, - } - } - - /// Whether this is an empty handle (`ctx == NULL`). - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. +pub use oakcore_rs::handle::CHandle; /// addref thunk: atomically increments the count. Shared by owned and /// borrowed boxes — for a borrowed handle addref only extends the life of @@ -260,7 +236,9 @@ mod tests { assert!(h.ctx.is_null()); assert!(h.addref.is_none()); assert!(h.release.is_none()); - assert_eq!(h.abi_version, OAKCOMMON_ABI_VERSION); + // The shared `null()` stamps no ABI version (single-lib + // unification; `make_owned` stamps the crate version). + assert_eq!(h.abi_version, 0); } #[test] diff --git a/src/common/rust/src/lib.rs b/src/common/rust/src/lib.rs index 564b744e0..4520f5f7c 100644 --- a/src/common/rust/src/lib.rs +++ b/src/common/rust/src/lib.rs @@ -23,6 +23,7 @@ pub mod colortransform; pub mod commandlineparser; +pub mod cancelatom; pub mod configstore; pub mod debug; pub mod error; diff --git a/src/common/rust/tests/ffi_colortransform.rs b/src/common/rust/tests/ffi_colortransform.rs index d29d9a6ad..75504249a 100644 --- a/src/common/rust/tests/ffi_colortransform.rs +++ b/src/common/rust/tests/ffi_colortransform.rs @@ -126,7 +126,8 @@ fn init_output_null_yields_null_handle() { assert!(h.ctx.is_null()); assert!(h.addref.is_none()); assert!(h.release.is_none()); - assert_eq!(h.abi_version, OAKCOMMON_ABI_VERSION); + // The shared `null()` stamps no ABI version (single-lib unification). + assert_eq!(h.abi_version, 0); } /// An empty output name is a valid value: the transform is still an output @@ -189,7 +190,8 @@ fn init_display_null_any_arg_yields_null_handle() { assert!(h.ctx.is_null()); assert!(h.addref.is_none()); assert!(h.release.is_none()); - assert_eq!(h.abi_version, OAKCOMMON_ABI_VERSION); + // The shared `null()` stamps no ABI version (single-lib unification). + assert_eq!(h.abi_version, 0); } } diff --git a/src/engine/rust/Cargo.lock b/src/engine/rust/Cargo.lock index 42ba8cd8e..c037f93b7 100644 --- a/src/engine/rust/Cargo.lock +++ b/src/engine/rust/Cargo.lock @@ -806,7 +806,9 @@ dependencies = [ name = "oaknode" version = "0.1.0" dependencies = [ + "oakcommon", "oakcore-rs", + "oakundo", ] [[package]] @@ -824,12 +826,14 @@ name = "oakplugin" version = "0.1.0" dependencies = [ "cc", + "oakcore-rs", ] [[package]] name = "oakrender" version = "0.1.0" dependencies = [ + "oakcommon", "oakcore-rs", "ocio-rs", "wgpu", diff --git a/src/engine/rust/src/audio.rs b/src/engine/rust/src/audio.rs index 26b84a02c..08bdd2ef6 100644 --- a/src/engine/rust/src/audio.rs +++ b/src/engine/rust/src/audio.rs @@ -327,10 +327,6 @@ pub unsafe extern "C" fn oakengine_audio_estimate_stretch_and_offset( confidence: 0.0, valid: 0, }; - // The module's rate search is fixed-step; the engine's range - // parameters are not part of its C ABI (documented deviation: - // the module searches its own default range). - let _ = (min_rate, max_rate, rate_step); Error::from_module(a::oakaudio_sync_estimate_stretch_and_offset( reference, reference_len, @@ -340,6 +336,9 @@ pub unsafe extern "C" fn oakengine_audio_estimate_stretch_and_offset( candidate_valid, window_samples, max_offset_windows, + min_rate, + max_rate, + rate_step, &mut result, ))?; (*out).rate = result.rate; diff --git a/src/engine/rust/src/bridge/audio.rs b/src/engine/rust/src/bridge/audio.rs index 03bf85066..239167b91 100644 --- a/src/engine/rust/src/bridge/audio.rs +++ b/src/engine/rust/src/bridge/audio.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oakaudio C ABI bridge: direct Rust calls into the `oakaudio` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oakaudio`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oakaudio C ABI imports, mirroring the oakaudio crate's exports //! (`src/audio/rust/src/ffi.rs`; headers `include/audio/*.h`), plus the //! liboakcore `oakcore_audioparams_*` readers used to convert the @@ -23,182 +50,21 @@ use std::ffi::{c_char, c_double, c_int, c_void}; use crate::handle::CHandle; -/// `oakaudio_sync_offset_result` mirror — `oak_audio_waveform_offset`. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct OffsetResult { - /// Offset of the candidate relative to the reference, in samples. - pub offset_samples: i64, - /// Normalized correlation confidence in `[0, 1]`. - pub confidence: c_double, - /// Whether an offset could be determined. - pub valid: c_int, -} +/// `oakaudio_offsetresult` C ABI POD. Single-lib unification: aliases +/// the oakaudio crate's struct (identical layout). +pub type OffsetResult = oakaudio::ffi::sync::OffsetResult; -/// `oakaudio_stretch_offset_result` mirror — `oak_audio_waveform_stretch_offset`. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct StretchOffsetResult { - /// Playback rate aligning the candidate (`> 1` = speed up). - pub rate: c_double, - /// Offset in samples. - pub offset_samples: i64, - /// Normalized correlation confidence in `[0, 1]`. - pub confidence: c_double, - /// Whether a rate+offset could be determined. - pub valid: c_int, -} -/// `oakaudio_sync_source_clip` mirror — `oak_audio_sync_source_clip`. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct SourceClip { - /// Source start time numerator (seconds). - pub source_start_time_num: i64, - /// Source start time denominator (seconds). - pub source_start_time_den: i64, - /// Media in point numerator (seconds). - pub media_in_num: i64, - /// Media in point denominator (seconds). - pub media_in_den: i64, - /// Whether `source_start_time` is set. - pub has_source_start_time: c_int, -} +/// `oakaudio_stretchoffsetresult` C ABI POD. Single-lib unification: aliases +/// the oakaudio crate's struct (identical layout). +pub type StretchOffsetResult = oakaudio::ffi::sync::StretchOffsetResult; -extern "C" { - // ---- manager.h -------------------------------------------------------- - /// `oakaudio_manager_create_instance` — create the singleton. - pub fn oakaudio_manager_create_instance() -> c_int; - /// `oakaudio_manager_destroy_instance` — destroy the singleton. - pub fn oakaudio_manager_destroy_instance(); - /// `oakaudio_manager_instance` — borrowed handle (empty when none). - pub fn oakaudio_manager_instance() -> CHandle; - /// `oakaudio_manager_free` — release a manager handle. - pub fn oakaudio_manager_free(_self: *mut CHandle); - /// `oakaudio_manager_set_output_notify_interval`. - pub fn oakaudio_manager_set_output_notify_interval(_self: CHandle, bytes: i64) -> c_int; - /// `oakaudio_manager_push_to_output`. - pub fn oakaudio_manager_push_to_output( - _self: CHandle, - rate: c_int, - layout: u64, - format: c_int, - samples: *const c_char, - samples_size: i64, - error_buf: *mut c_char, - error_buf_size: c_int, - ) -> c_int; - /// `oakaudio_manager_clear_buffered_output`. - pub fn oakaudio_manager_clear_buffered_output(_self: CHandle) -> c_int; - /// `oakaudio_manager_stop_output`. - pub fn oakaudio_manager_stop_output(_self: CHandle) -> c_int; - /// `oakaudio_manager_reset_output_clock`. - pub fn oakaudio_manager_reset_output_clock(_self: CHandle) -> c_int; - /// `oakaudio_manager_get_output_device` — module returns the device as - /// `c_int`; the facade widens to the engine's int64_t. - pub fn oakaudio_manager_get_output_device(_self: CHandle) -> c_int; - /// `oakaudio_manager_set_output_device`. - pub fn oakaudio_manager_set_output_device(_self: CHandle, device: c_int) -> c_int; - /// `oakaudio_manager_get_input_device`. - pub fn oakaudio_manager_get_input_device(_self: CHandle) -> c_int; - /// `oakaudio_manager_set_input_device`. - pub fn oakaudio_manager_set_input_device(_self: CHandle, device: c_int) -> c_int; - /// `oakaudio_manager_hard_reset`. - pub fn oakaudio_manager_hard_reset(_self: CHandle) -> c_int; - /// `oakaudio_manager_start_recording`. - pub fn oakaudio_manager_start_recording( - _self: CHandle, - params: *const EncodingParams, - error_buf: *mut c_char, - error_buf_size: c_int, - ) -> c_int; - /// `oakaudio_manager_stop_recording`. - pub fn oakaudio_manager_stop_recording(_self: CHandle) -> c_int; - /// `oakaudio_manager_seconds`. - pub fn oakaudio_manager_seconds(_self: CHandle) -> i64; - // ---- processor.h ------------------------------------------------------ - /// `oakaudio_processor_init` — new processor, refcount 1. - pub fn oakaudio_processor_init() -> CHandle; - /// `oakaudio_processor_free` — NULL/empty no-op. - pub fn oakaudio_processor_free(_self: *mut CHandle); - /// `oakaudio_processor_open`. - pub fn oakaudio_processor_open( - _self: CHandle, - in_rate: c_int, - in_layout: u64, - in_format: c_int, - out_rate: c_int, - out_layout: u64, - out_format: c_int, - speed: c_double, - ) -> c_int; - /// `oakaudio_processor_close`. - pub fn oakaudio_processor_close(_self: CHandle) -> c_int; - /// `oakaudio_processor_is_open`. - pub fn oakaudio_processor_is_open(_self: CHandle) -> c_int; +/// `oakaudio_sourceclip` C ABI POD. Single-lib unification: aliases +/// the oakaudio crate's struct (identical layout). +pub type SourceClip = oakaudio::ffi::sync::SourceClip; - // ---- sync.h ----------------------------------------------------------- - /// `oakaudio_sync_estimate_envelope_offset`. - pub fn oakaudio_sync_estimate_envelope_offset( - reference: *const c_double, - reference_len: c_int, - candidate: *const c_double, - candidate_len: c_int, - reference_valid: *const u8, - candidate_valid: *const u8, - window_samples: u64, - max_offset_windows: i64, - out: *mut OffsetResult, - ) -> c_int; - /// `oakaudio_sync_estimate_stretch_and_offset`. - pub fn oakaudio_sync_estimate_stretch_and_offset( - reference: *const c_double, - reference_len: c_int, - candidate: *const c_double, - candidate_len: c_int, - reference_valid: *const u8, - candidate_valid: *const u8, - window_samples: u64, - max_offset_windows: i64, - out: *mut StretchOffsetResult, - ) -> c_int; - /// `oakaudio_sync_place_by_source_time`. - pub fn oakaudio_sync_place_by_source_time( - reference: *const SourceClip, - candidate: *const SourceClip, - reference_timeline_in_num: i64, - reference_timeline_in_den: i64, - out_num: *mut i64, - out_den: *mut i64, - out_valid: *mut c_int, - ) -> c_int; - /// `oakaudio_sync_place_by_waveform_offset`. - pub fn oakaudio_sync_place_by_waveform_offset( - reference_timeline_in_num: i64, - reference_timeline_in_den: i64, - candidate_offset_samples: i64, - sample_rate: c_int, - out_num: *mut i64, - out_den: *mut i64, - out_valid: *mut c_int, - ) -> c_int; - // ---- liboakcore (oakcore_audioparams_*) -------------------------------- - /// `oakcore_audioparams_create` — new owned params (release with - /// [`oakcore_audioparams_free`]). - pub fn oakcore_audioparams_create(sample_rate: c_int, channel_layout: u64, format: c_int) -> *mut c_void; - /// `oakcore_audioparams_free` — release params created by - /// [`oakcore_audioparams_create`] (or returned by the oaknode sequence - /// audio-params getter). - pub fn oakcore_audioparams_free(params: *mut c_void); - /// `oakcore_audioparams_sample_rate` — borrowed params reader. - pub fn oakcore_audioparams_sample_rate(params: *const c_void) -> c_int; - /// `oakcore_audioparams_channel_layout` — borrowed params reader. - pub fn oakcore_audioparams_channel_layout(params: *const c_void) -> u64; - /// `oakcore_audioparams_format` — borrowed params reader. - pub fn oakcore_audioparams_format(params: *const c_void) -> c_int; -} /// Opaque mirror of the oakaudio recording-params POD /// (`include/audio/manager.h`). The facade passes the engine's @@ -208,3 +74,244 @@ extern "C" { pub struct EncodingParams { _opaque: [u8; 0], } + +extern "C" { + pub fn oakcore_audioparams_create(sample_rate: c_int, channel_layout: u64, format: c_int) -> *mut c_void; + pub fn oakcore_audioparams_free(params: *mut c_void); + pub fn oakcore_audioparams_sample_rate(params: *const c_void) -> c_int; + pub fn oakcore_audioparams_channel_layout(params: *const c_void) -> u64; + pub fn oakcore_audioparams_format(params: *const c_void) -> c_int; +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_create_instance() -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_create_instance() } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_destroy_instance() { + unsafe { oakaudio::ffi::manager::oakaudio_manager_destroy_instance() } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_instance() -> CHandle { + unsafe { oakaudio::ffi::manager::oakaudio_manager_instance() } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_free(_self: *mut CHandle) { + unsafe { oakaudio::ffi::manager::oakaudio_manager_free(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_set_output_notify_interval(_self: CHandle, bytes: i64) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_set_output_notify_interval(_self, bytes) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_push_to_output( + _self: CHandle, + rate: c_int, + layout: u64, + format: c_int, + samples: *const c_char, + samples_size: i64, + error_buf: *mut c_char, + error_buf_size: c_int, + ) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_push_to_output(_self, rate, layout, format, samples, samples_size, error_buf, error_buf_size) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_clear_buffered_output(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_clear_buffered_output(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_stop_output(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_stop_output(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_reset_output_clock(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_reset_output_clock(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_get_output_device(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_get_output_device(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_set_output_device(_self: CHandle, device: c_int) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_set_output_device(_self, device) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_get_input_device(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_get_input_device(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_set_input_device(_self: CHandle, device: c_int) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_set_input_device(_self, device) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_hard_reset(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_hard_reset(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +/// `oakaudio_manager_start_recording` — crosses the encoding-params C ABI +/// POD (the facade keeps its own opaque mirror; the module's +/// `oakaudio::bridge::codec::EncodingParams`). Kept as a link-time +/// `extern "C"` declaration against the frozen module C ABI. +pub fn oakaudio_manager_start_recording( + _self: CHandle, + params: *const EncodingParams, + error_buf: *mut c_char, + error_buf_size: c_int, +) -> c_int { + unsafe { oakaudio_start_recording_extern(_self, params, error_buf, error_buf_size) } +} + +extern "C" { + #[link_name = "oakaudio_manager_start_recording"] + pub fn oakaudio_start_recording_extern( + _self: CHandle, + params: *const EncodingParams, + error_buf: *mut c_char, + error_buf_size: c_int, + ) -> c_int; +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_stop_recording(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_stop_recording(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_manager_seconds(_self: CHandle, out: *mut c_double) -> c_int { + unsafe { oakaudio::ffi::manager::oakaudio_manager_seconds(_self, out) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_processor_init() -> CHandle { + unsafe { oakaudio::ffi::processor::oakaudio_processor_init() } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_processor_free(_self: *mut CHandle) { + unsafe { oakaudio::ffi::processor::oakaudio_processor_free(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_processor_open( + _self: CHandle, + in_rate: c_int, + in_layout: u64, + in_format: c_int, + out_rate: c_int, + out_layout: u64, + out_format: c_int, + speed: c_double, + ) -> c_int { + unsafe { oakaudio::ffi::processor::oakaudio_processor_open(_self, in_rate, in_layout, in_format, out_rate, out_layout, out_format, speed) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_processor_close(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::processor::oakaudio_processor_close(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_processor_is_open(_self: CHandle) -> c_int { + unsafe { oakaudio::ffi::processor::oakaudio_processor_is_open(_self) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_sync_estimate_envelope_offset( + reference: *const c_double, + reference_len: c_int, + candidate: *const c_double, + candidate_len: c_int, + reference_valid: *const u8, + candidate_valid: *const u8, + window_samples: u64, + max_offset_windows: i64, + out: *mut OffsetResult, + ) -> c_int { + unsafe { oakaudio::ffi::sync::oakaudio_sync_estimate_envelope_offset(reference, reference_len, candidate, candidate_len, reference_valid, candidate_valid, window_samples, max_offset_windows, out) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_sync_estimate_stretch_and_offset( + reference: *const c_double, + reference_len: c_int, + candidate: *const c_double, + candidate_len: c_int, + reference_valid: *const u8, + candidate_valid: *const u8, + window_samples: u64, + max_offset_windows: i64, + min_rate: c_double, + max_rate: c_double, + rate_step: c_double, + out: *mut StretchOffsetResult, + ) -> c_int { + unsafe { oakaudio::ffi::sync::oakaudio_sync_estimate_stretch_and_offset(reference, reference_len, candidate, candidate_len, reference_valid, candidate_valid, window_samples, max_offset_windows, min_rate, max_rate, rate_step, out) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_sync_place_by_source_time( + reference: *const SourceClip, + candidate: *const SourceClip, + reference_timeline_in_num: i64, + reference_timeline_in_den: i64, + out_num: *mut i64, + out_den: *mut i64, + out_valid: *mut c_int, + ) -> c_int { + unsafe { oakaudio::ffi::sync::oakaudio_sync_place_by_source_time(reference, candidate, reference_timeline_in_num, reference_timeline_in_den, out_num, out_den, out_valid) } +} + +/// Direct call into the `oakaudio` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakaudio_sync_place_by_waveform_offset( + reference_timeline_in_num: i64, + reference_timeline_in_den: i64, + candidate_offset_samples: i64, + sample_rate: c_int, + out_num: *mut i64, + out_den: *mut i64, + out_valid: *mut c_int, + ) -> c_int { + unsafe { oakaudio::ffi::sync::oakaudio_sync_place_by_waveform_offset(reference_timeline_in_num, reference_timeline_in_den, candidate_offset_samples, sample_rate, out_num, out_den, out_valid) } +} + diff --git a/src/engine/rust/src/bridge/codec.rs b/src/engine/rust/src/bridge/codec.rs index 340b03f38..bdc6bb5bc 100644 --- a/src/engine/rust/src/bridge/codec.rs +++ b/src/engine/rust/src/bridge/codec.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oakcodec C ABI bridge: direct Rust calls into the `oakcodec` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oakcodec`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oakcodec C ABI imports, mirroring the oakcodec crate's exports //! (`src/codec/rust/src/ffi/{format,encoder}.rs`; headers //! `include/codec/{format,encoder}.h`). Also carries the @@ -117,76 +144,171 @@ impl EncodingParamsPOD { } } -extern "C" { - // ---- include/codec/format.h (encoding metadata) ------------------------ - /// `oakcodec_encoding_format_count`. - pub fn oakcodec_encoding_format_count() -> c_int; - /// `oakcodec_encoding_format_name` (two-stage string). - pub fn oakcodec_encoding_format_name(format: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oakcodec_encoding_format_extension` (two-stage string). - pub fn oakcodec_encoding_format_extension( +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_count() -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_count() } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_name(format: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_name(format, buf, buf_size) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_extension( format: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcodec_encoding_format_video_codec_count`. - pub fn oakcodec_encoding_format_video_codec_count(format: c_int) -> c_int; - /// `oakcodec_encoding_format_video_codec_at`. - pub fn oakcodec_encoding_format_video_codec_at(format: c_int, index: c_int) -> c_int; - /// `oakcodec_encoding_format_audio_codec_count`. - pub fn oakcodec_encoding_format_audio_codec_count(format: c_int) -> c_int; - /// `oakcodec_encoding_format_audio_codec_at`. - pub fn oakcodec_encoding_format_audio_codec_at(format: c_int, index: c_int) -> c_int; - /// `oakcodec_encoding_format_subtitle_codec_count`. - pub fn oakcodec_encoding_format_subtitle_codec_count(format: c_int) -> c_int; - /// `oakcodec_encoding_format_subtitle_codec_at`. - pub fn oakcodec_encoding_format_subtitle_codec_at(format: c_int, index: c_int) -> c_int; - /// `oakcodec_encoding_codec_name` (two-stage string). - pub fn oakcodec_encoding_codec_name(codec: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oakcodec_encoding_codec_is_still_image`. - pub fn oakcodec_encoding_codec_is_still_image(codec: c_int) -> c_int; - /// `oakcodec_encoding_codec_is_lossless`. - pub fn oakcodec_encoding_codec_is_lossless(codec: c_int) -> c_int; - /// `oakcodec_encoding_pix_fmt_count`. - pub fn oakcodec_encoding_pix_fmt_count(format: c_int, codec: c_int) -> c_int; - /// `oakcodec_encoding_pix_fmt_at` (two-stage string). - pub fn oakcodec_encoding_pix_fmt_at( + ) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_extension(format, buf, buf_size) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_video_codec_count(format: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_video_codec_count(format) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_video_codec_at(format: c_int, index: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_video_codec_at(format, index) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_audio_codec_count(format: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_audio_codec_count(format) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_audio_codec_at(format: c_int, index: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_audio_codec_at(format, index) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_subtitle_codec_count(format: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_subtitle_codec_count(format) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_format_subtitle_codec_at(format: c_int, index: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_format_subtitle_codec_at(format, index) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_codec_name(codec: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_codec_name(codec, buf, buf_size) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_codec_is_still_image(codec: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_codec_is_still_image(codec) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_codec_is_lossless(codec: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_codec_is_lossless(codec) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_pix_fmt_count(format: c_int, codec: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_pix_fmt_count(format, codec) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_pix_fmt_at( format: c_int, codec: c_int, index: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcodec_encoding_pix_fmt_index`. - pub fn oakcodec_encoding_pix_fmt_index(codec: c_int, pix_fmt: *const c_char) -> c_int; - /// `oakcodec_encoding_sample_format_count`. - pub fn oakcodec_encoding_sample_format_count(format: c_int, codec: c_int) -> c_int; - /// `oakcodec_encoding_sample_format_at`. - pub fn oakcodec_encoding_sample_format_at(format: c_int, codec: c_int, index: c_int) -> c_int; - /// `oakcodec_encoding_filename_contains_digit_placeholder` (0 for NULL). - pub fn oakcodec_encoding_filename_contains_digit_placeholder(filename: *const c_char) -> c_int; - /// `oakcodec_encoding_image_sequence_digit_count` (0 when none). - pub fn oakcodec_encoding_image_sequence_digit_count(filename: *const c_char) -> c_int; - /// `oakcodec_encoding_filename_remove_digit_placeholder` (two-stage). - pub fn oakcodec_encoding_filename_remove_digit_placeholder( + ) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_pix_fmt_at(format, codec, index, buf, buf_size) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_pix_fmt_index(codec: c_int, pix_fmt: *const c_char) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_pix_fmt_index(codec, pix_fmt) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_sample_format_count(format: c_int, codec: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_sample_format_count(format, codec) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_sample_format_at(format: c_int, codec: c_int, index: c_int) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_sample_format_at(format, codec, index) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_filename_contains_digit_placeholder(filename: *const c_char) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_filename_contains_digit_placeholder(filename) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_image_sequence_digit_count(filename: *const c_char) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_image_sequence_digit_count(filename) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_filename_remove_digit_placeholder( filename: *const c_char, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcodec_encoding_generate_matrix` — writes 16 `f64` (the engine - /// surface uses `f32`; the facade converts). - pub fn oakcodec_encoding_generate_matrix( + ) -> c_int { + unsafe { oakcodec::ffi::format::oakcodec_encoding_filename_remove_digit_placeholder(filename, buf, buf_size) } +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoding_generate_matrix( method: c_int, src_width: c_int, src_height: c_int, dst_width: c_int, dst_height: c_int, out_matrix: *mut f64, - ) -> c_int; - - // ---- include/codec/encoder.h ------------------------------------------- - /// `oakcodec_encoder_init` — encoder over a params POD (refcount 1). - pub fn oakcodec_encoder_init(params: *const EncodingParamsPOD) -> CHandle; - /// `oakcodec_encoder_free` — NULL/empty no-op. - pub fn oakcodec_encoder_free(encoder: *mut CHandle); + ) -> c_int { + unsafe { oakcodec::ffi::encoder::oakcodec_encoding_generate_matrix(method, src_width, src_height, dst_width, dst_height, out_matrix) } } + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +/// `oakcodec_encoder_init` — crosses the encoding-params C ABI POD +/// (`oakcodec_encoding_params`; the facade keeps its own POD mirror). +/// Kept as a link-time `extern "C"` declaration against the frozen module +/// C ABI. +pub fn oakcodec_encoder_init(params: *const EncodingParamsPOD) -> CHandle { + unsafe { oakcodec_encoder_init_extern(params) } +} + +extern "C" { + #[link_name = "oakcodec_encoder_init"] + pub fn oakcodec_encoder_init_extern(params: *const EncodingParamsPOD) -> CHandle; +} + +/// Direct call into the `oakcodec` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcodec_encoder_free(encoder: *mut CHandle) { + unsafe { oakcodec::ffi::encoder::oakcodec_encoder_free(encoder) } +} + diff --git a/src/engine/rust/src/bridge/common.rs b/src/engine/rust/src/bridge/common.rs index ee67021c2..9682f8b82 100644 --- a/src/engine/rust/src/bridge/common.rs +++ b/src/engine/rust/src/bridge/common.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oakcommon C ABI bridge: direct Rust calls into the `oakcommon` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oakcommon`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oakcommon C ABI imports, mirroring the oakcommon crate's exports //! (`src/common/rust/src/ffi.rs`; headers `include/common/*.h`). Only the //! families the facade wraps: config, videoparams, colortransform, xml @@ -27,316 +54,686 @@ use crate::handle::CHandle; pub type ConfigErrorHandler = Option; -extern "C" { - // ---- config.h ------------------------------------------------------- - /// `oakcommon_config_load` — reset to defaults, then read config.ini. - pub fn oakcommon_config_load() -> c_int; - /// `oakcommon_config_save` — write config.ini (temp file + rename). - pub fn oakcommon_config_save() -> c_int; - /// `oakcommon_config_reset_defaults` — drop custom keys. - pub fn oakcommon_config_reset_defaults() -> c_int; - /// `oakcommon_config_set` — set a string entry. - pub fn oakcommon_config_set(group: *const c_char, key: *const c_char, value: *const c_char); - /// `oakcommon_config_get` — read an entry as string (two-stage). - pub fn oakcommon_config_get( +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_load() -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_load() } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_save() -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_save() } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_reset_defaults() -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_reset_defaults() } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_set(group: *const c_char, key: *const c_char, value: *const c_char) { + unsafe { oakcommon::ffi::config::oakcommon_config_set(group, key, value) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_get( group: *const c_char, key: *const c_char, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcommon_config_get_int` — INT entry with fallback. - pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int; - /// `oakcommon_config_get_int64` — INT64 entry with fallback. - pub fn oakcommon_config_get_int64( + ) -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_get(group, key, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_get_int(group, key, fallback) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_get_int64( group: *const c_char, key: *const c_char, fallback: i64, - ) -> i64; - /// `oakcommon_config_get_double` — DOUBLE entry with fallback. - pub fn oakcommon_config_get_double(group: *const c_char, key: *const c_char, fallback: f64) -> f64; - /// `oakcommon_config_get_bool` — BOOL entry with fallback. - pub fn oakcommon_config_get_bool(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int; - /// `oakcommon_config_set_int` — set an INT entry. - pub fn oakcommon_config_set_int(group: *const c_char, key: *const c_char, value: c_int); - /// `oakcommon_config_set_int64` — set an INT64 entry. - pub fn oakcommon_config_set_int64(group: *const c_char, key: *const c_char, value: i64); - /// `oakcommon_config_set_double` — set a DOUBLE entry. - pub fn oakcommon_config_set_double(group: *const c_char, key: *const c_char, value: f64); - /// `oakcommon_config_set_bool` — set a BOOL entry. - pub fn oakcommon_config_set_bool(group: *const c_char, key: *const c_char, value: c_int); - /// `oakcommon_config_entry_type` — the entry's declared type. - pub fn oakcommon_config_entry_type(group: *const c_char, key: *const c_char) -> c_int; - /// `oakcommon_config_set_error_handler` — install the UI error handler. - pub fn oakcommon_config_set_error_handler(handler: ConfigErrorHandler, userdata: *mut c_void) -> c_int; + ) -> i64 { + unsafe { oakcommon::ffi::config::oakcommon_config_get_int64(group, key, fallback) } +} - // ---- videoparams.h -------------------------------------------------- - /// `oakcommon_videoparams_init` — default video params, refcount 1. - pub fn oakcommon_videoparams_init() -> CHandle; - /// `oakcommon_videoparams_init_basic` — width/height/frame-rate params. - pub fn oakcommon_videoparams_init_basic( - width: c_int, - height: c_int, - time_base_num: c_int, - time_base_den: c_int, - ) -> CHandle; - /// `oakcommon_videoparams_init_with_time_base` — params + time base. - pub fn oakcommon_videoparams_init_with_time_base( - width: c_int, - height: c_int, - time_base_num: c_int, - time_base_den: c_int, - ) -> CHandle; - /// `oakcommon_videoparams_free` — NULL/empty no-op; clears `params->ctx`. - pub fn oakcommon_videoparams_free(params: *mut CHandle); - /// `oakcommon_videoparams_get_width`. - pub fn oakcommon_videoparams_get_width(params: CHandle, width: *mut c_int) -> c_int; - /// `oakcommon_videoparams_set_width`. - pub fn oakcommon_videoparams_set_width(params: CHandle, width: c_int) -> c_int; - /// `oakcommon_videoparams_get_height`. - pub fn oakcommon_videoparams_get_height(params: CHandle, height: *mut c_int) -> c_int; - /// `oakcommon_videoparams_set_height`. - pub fn oakcommon_videoparams_set_height(params: CHandle, height: c_int) -> c_int; - /// `oakcommon_videoparams_get_time_base`. - pub fn oakcommon_videoparams_get_time_base( +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_get_double(group: *const c_char, key: *const c_char, fallback: f64) -> f64 { + unsafe { oakcommon::ffi::config::oakcommon_config_get_double(group, key, fallback) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_get_bool(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_get_bool(group, key, fallback) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_set_int(group: *const c_char, key: *const c_char, value: c_int) { + unsafe { oakcommon::ffi::config::oakcommon_config_set_int(group, key, value) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_set_int64(group: *const c_char, key: *const c_char, value: i64) { + unsafe { oakcommon::ffi::config::oakcommon_config_set_int64(group, key, value) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_set_double(group: *const c_char, key: *const c_char, value: f64) { + unsafe { oakcommon::ffi::config::oakcommon_config_set_double(group, key, value) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_set_bool(group: *const c_char, key: *const c_char, value: c_int) { + unsafe { oakcommon::ffi::config::oakcommon_config_set_bool(group, key, value) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_entry_type(group: *const c_char, key: *const c_char) -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_entry_type(group, key) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_config_set_error_handler(handler: ConfigErrorHandler, userdata: *mut c_void) -> c_int { + unsafe { oakcommon::ffi::config::oakcommon_config_set_error_handler(handler, userdata) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_init() -> CHandle { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_init() } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_init_basic( + width: c_int, + height: c_int, + pixel_format: c_int, + nb_channels: c_int, + pixel_aspect_num: c_int, + pixel_aspect_den: c_int, + interlacing: c_int, + divider: c_int, +) -> CHandle { + unsafe { + oakcommon::ffi::videoparams::oakcommon_videoparams_init_basic( + width, height, pixel_format, nb_channels, pixel_aspect_num, pixel_aspect_den, + interlacing, divider, + ) + } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_init_with_time_base( + width: c_int, + height: c_int, + time_base_num: c_int, + time_base_den: c_int, + pixel_format: c_int, + nb_channels: c_int, + pixel_aspect_num: c_int, + pixel_aspect_den: c_int, + interlacing: c_int, + divider: c_int, +) -> CHandle { + unsafe { + oakcommon::ffi::videoparams::oakcommon_videoparams_init_with_time_base( + width, height, time_base_num, time_base_den, pixel_format, nb_channels, + pixel_aspect_num, pixel_aspect_den, interlacing, divider, + ) + } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_free(params: *mut CHandle) { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_free(params) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_width(params: CHandle, width: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_width(params, width) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_width(params: CHandle, width: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_width(params, width) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_height(params: CHandle, height: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_height(params, height) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_height(params: CHandle, height: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_height(params, height) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_time_base( params: CHandle, numerator: *mut c_int, denominator: *mut c_int, - ) -> c_int; - /// `oakcommon_videoparams_set_time_base`. - pub fn oakcommon_videoparams_set_time_base( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_time_base(params, numerator, denominator) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_time_base( params: CHandle, numerator: c_int, denominator: c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_frame_rate`. - pub fn oakcommon_videoparams_get_frame_rate( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_time_base(params, numerator, denominator) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_frame_rate( params: CHandle, numerator: *mut c_int, denominator: *mut c_int, - ) -> c_int; - /// `oakcommon_videoparams_set_frame_rate`. - pub fn oakcommon_videoparams_set_frame_rate( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_frame_rate(params, numerator, denominator) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_frame_rate( params: CHandle, numerator: c_int, denominator: c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_pixel_aspect_ratio`. - pub fn oakcommon_videoparams_get_pixel_aspect_ratio( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_frame_rate(params, numerator, denominator) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_pixel_aspect_ratio( params: CHandle, numerator: *mut c_int, denominator: *mut c_int, - ) -> c_int; - /// `oakcommon_videoparams_set_pixel_aspect_ratio`. - pub fn oakcommon_videoparams_set_pixel_aspect_ratio( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_pixel_aspect_ratio(params, numerator, denominator) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_pixel_aspect_ratio( params: CHandle, numerator: c_int, denominator: c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_format`. - pub fn oakcommon_videoparams_get_format(params: CHandle, format: *mut c_int) -> c_int; - /// `oakcommon_videoparams_set_format`. - pub fn oakcommon_videoparams_set_format(params: CHandle, format: c_int) -> c_int; - /// `oakcommon_videoparams_get_interlacing`. - pub fn oakcommon_videoparams_get_interlacing(params: CHandle, interlacing: *mut c_int) -> c_int; - /// `oakcommon_videoparams_set_interlacing`. - pub fn oakcommon_videoparams_set_interlacing(params: CHandle, interlacing: c_int) -> c_int; - /// `oakcommon_videoparams_get_divider`. - pub fn oakcommon_videoparams_get_divider(params: CHandle, divider: *mut c_int) -> c_int; - /// `oakcommon_videoparams_set_divider`. - pub fn oakcommon_videoparams_set_divider(params: CHandle, divider: c_int) -> c_int; - /// `oakcommon_videoparams_get_video_type`. - pub fn oakcommon_videoparams_get_video_type(params: CHandle, type_: *mut c_int) -> c_int; - /// `oakcommon_videoparams_set_video_type`. - pub fn oakcommon_videoparams_set_video_type(params: CHandle, type_: c_int) -> c_int; - /// `oakcommon_videoparams_get_premultiplied_alpha`. - pub fn oakcommon_videoparams_get_premultiplied_alpha( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_pixel_aspect_ratio(params, numerator, denominator) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_format(params: CHandle, format: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_format(params, format) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_format(params: CHandle, format: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_format(params, format) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_interlacing(params: CHandle, interlacing: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_interlacing(params, interlacing) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_interlacing(params: CHandle, interlacing: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_interlacing(params, interlacing) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_divider(params: CHandle, divider: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_divider(params, divider) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_divider(params: CHandle, divider: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_divider(params, divider) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_video_type(params: CHandle, type_: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_video_type(params, type_) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_video_type(params: CHandle, type_: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_video_type(params, type_) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_premultiplied_alpha( params: CHandle, premultiplied: *mut c_int, - ) -> c_int; - /// `oakcommon_videoparams_set_premultiplied_alpha`. - pub fn oakcommon_videoparams_set_premultiplied_alpha(params: CHandle, premultiplied: c_int) -> c_int; - /// `oakcommon_videoparams_get_color_range`. - pub fn oakcommon_videoparams_get_color_range(params: CHandle, color_range: *mut c_int) -> c_int; - /// `oakcommon_videoparams_set_color_range`. - pub fn oakcommon_videoparams_set_color_range(params: CHandle, color_range: c_int) -> c_int; - /// `oakcommon_videoparams_get_is_valid`. - pub fn oakcommon_videoparams_get_is_valid(params: CHandle, valid: *mut c_int) -> c_int; - /// `oakcommon_videoparams_get_effective_width` — divider-scaled width. - pub fn oakcommon_videoparams_get_effective_width(params: CHandle, width: *mut c_int) -> c_int; - /// `oakcommon_videoparams_get_effective_height` — divider-scaled height. - pub fn oakcommon_videoparams_get_effective_height(params: CHandle, height: *mut c_int) -> c_int; - /// `oakcommon_videoparams_get_bytes_per_pixel` — with the params' format. - pub fn oakcommon_videoparams_get_bytes_per_pixel(params: CHandle, bytes: *mut c_int) -> c_int; - /// `oakcommon_videoparams_equals` — user-facing field equality. - pub fn oakcommon_videoparams_equals(a: CHandle, b: CHandle, out_equal: *mut c_int) -> c_int; - /// `oakcommon_videoparams_format_is_float` — 1 when the format is float. - pub fn oakcommon_videoparams_format_is_float(pixel_format: c_int) -> c_int; - /// `oakcommon_videoparams_get_format_name` — display name (two-stage). - pub fn oakcommon_videoparams_get_format_name( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_premultiplied_alpha(params, premultiplied) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_premultiplied_alpha(params: CHandle, premultiplied: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_premultiplied_alpha(params, premultiplied) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_color_range(params: CHandle, color_range: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_color_range(params, color_range) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_set_color_range(params: CHandle, color_range: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_color_range(params, color_range) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_is_valid(params: CHandle, valid: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_is_valid(params, valid) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_effective_width(params: CHandle, width: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_effective_width(params, width) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_effective_height(params: CHandle, height: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_effective_height(params, height) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_bytes_per_pixel(params: CHandle, bytes: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_bytes_per_pixel(params, bytes) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_equals(a: CHandle, b: CHandle, out_equal: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_equals(a, b, out_equal) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_format_is_float(pixel_format: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_format_is_float(pixel_format) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_format_name( pixel_format: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcommon_videoparams_frame_rate_to_string` — label (two-stage). - pub fn oakcommon_videoparams_frame_rate_to_string( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_format_name(pixel_format, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_frame_rate_to_string( numerator: c_int, denominator: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_name_for_divider` — label (two-stage). - pub fn oakcommon_videoparams_get_name_for_divider( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_frame_rate_to_string(numerator, denominator, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_name_for_divider( divider: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_scaled_dimension` — size at a divider. - pub fn oakcommon_videoparams_get_scaled_dimension(dimension: c_int, divider: c_int) -> c_int; - /// `oakcommon_videoparams_generate_auto_divider` — best divider for size. - pub fn oakcommon_videoparams_generate_auto_divider(width: i64, height: i64) -> c_int; - /// `oakcommon_videoparams_get_divider_for_target_resolution`. - pub fn oakcommon_videoparams_get_divider_for_target_resolution( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_name_for_divider(divider, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_scaled_dimension(dimension: c_int, divider: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_scaled_dimension(dimension, divider) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_generate_auto_divider(width: i64, height: i64) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_generate_auto_divider(width, height) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_divider_for_target_resolution( src_width: c_int, src_height: c_int, target_width: c_int, target_height: c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_bytes_per_channel_for_format`. - pub fn oakcommon_videoparams_get_bytes_per_channel_for_format( - pixel_format: c_int, - bytes: *mut c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_bytes_per_pixel_for_format`. - pub fn oakcommon_videoparams_get_bytes_per_pixel_for_format( - pixel_format: c_int, - bytes: *mut c_int, - ) -> c_int; - /// `oakcommon_videoparams_static_get_bytes_per_pixel`. - pub fn oakcommon_videoparams_static_get_bytes_per_pixel( + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_divider_for_target_resolution(src_width, src_height, target_width, target_height) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_bytes_per_channel_for_format(pixel_format: c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_bytes_per_channel_for_format(pixel_format) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_bytes_per_pixel_for_format( + pixel_format: c_int, + channels: c_int, +) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_bytes_per_pixel_for_format(pixel_format, channels) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_static_get_bytes_per_pixel( pixel_format: c_int, channels: c_int, - ) -> c_int; - /// `oakcommon_videoparams_get_buffer_size`. - pub fn oakcommon_videoparams_get_buffer_size(params: CHandle, bytes: *mut i64) -> c_int; - /// `oakcommon_videoparams_get_time_in_timebase_units`. - pub fn oakcommon_videoparams_get_time_in_timebase_units( - params: CHandle, - time_num: i64, - time_den: i64, - out: *mut i64, - ) -> c_int; + ) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_static_get_bytes_per_pixel(pixel_format, channels) } +} - // ---- colortransform.h ----------------------------------------------- - /// `oakcommon_colortransform_init_output` — output color space transform. - pub fn oakcommon_colortransform_init_output(output: *const c_char) -> CHandle; - /// `oakcommon_colortransform_init_display` — display/view/look transform. - pub fn oakcommon_colortransform_init_display( +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_buffer_size(params: CHandle, size: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_buffer_size(params, size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_videoparams_get_time_in_timebase_units( + params: CHandle, + time_num: c_int, + time_den: c_int, + timestamp: *mut i64, +) -> c_int { + unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_time_in_timebase_units(params, time_num, time_den, timestamp) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_init_output(output: *const c_char) -> CHandle { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_init_output(output) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_init_display( display: *const c_char, view: *const c_char, look: *const c_char, - ) -> CHandle; - /// `oakcommon_colortransform_free` — NULL/empty no-op. - pub fn oakcommon_colortransform_free(transform: *mut CHandle); - /// `oakcommon_colortransform_is_display` — 1 for a display transform. - pub fn oakcommon_colortransform_is_display(transform: CHandle) -> c_int; - /// `oakcommon_colortransform_get_display` (two-stage string). - pub fn oakcommon_colortransform_get_display( - transform: CHandle, - buf: *mut c_char, - buf_size: c_int, - ) -> c_int; - /// `oakcommon_colortransform_get_output` (two-stage string). - pub fn oakcommon_colortransform_get_output( - transform: CHandle, - buf: *mut c_char, - buf_size: c_int, - ) -> c_int; - /// `oakcommon_colortransform_get_view` (two-stage string). - pub fn oakcommon_colortransform_get_view( - transform: CHandle, - buf: *mut c_char, - buf_size: c_int, - ) -> c_int; - /// `oakcommon_colortransform_get_look` (two-stage string). - pub fn oakcommon_colortransform_get_look( - transform: CHandle, - buf: *mut c_char, - buf_size: c_int, - ) -> c_int; + ) -> CHandle { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_init_display(display, view, look) } +} - // ---- xmlutils.h ----------------------------------------------------- - /// `oakcommon_xml_reader_init` — reader over a NUL-terminated document. - pub fn oakcommon_xml_reader_init(data: *const c_char) -> CHandle; - /// `oakcommon_xml_reader_free` — NULL/empty no-op. - pub fn oakcommon_xml_reader_free(reader: *mut CHandle); - /// `oakcommon_xml_reader_read_next_start_element` — found 1/0 in `found`. - pub fn oakcommon_xml_reader_read_next_start_element(reader: CHandle, found: *mut c_int) -> c_int; - /// `oakcommon_xml_reader_name` (two-stage string). - pub fn oakcommon_xml_reader_name(reader: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oakcommon_xml_reader_read_element_text` (two-stage string). - pub fn oakcommon_xml_reader_read_element_text( +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_free(transform: *mut CHandle) { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_free(transform) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_is_display(transform: CHandle) -> c_int { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_is_display(transform) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_get_display( + transform: CHandle, + buf: *mut c_char, + buf_size: c_int, + ) -> c_int { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_display(transform, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_get_output( + transform: CHandle, + buf: *mut c_char, + buf_size: c_int, + ) -> c_int { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_output(transform, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_get_view( + transform: CHandle, + buf: *mut c_char, + buf_size: c_int, + ) -> c_int { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_view(transform, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_colortransform_get_look( + transform: CHandle, + buf: *mut c_char, + buf_size: c_int, + ) -> c_int { + unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_look(transform, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_init(data: *const c_char) -> CHandle { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_init(data) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_free(reader: *mut CHandle) { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_free(reader) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_read_next_start_element(reader: CHandle, found: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_read_next_start_element(reader, found) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_name(reader: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_name(reader, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_read_element_text( reader: CHandle, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcommon_xml_reader_skip_current_element`. - pub fn oakcommon_xml_reader_skip_current_element(reader: CHandle) -> c_int; - /// `oakcommon_xml_reader_attribute_count`. - pub fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int; - /// `oakcommon_xml_reader_attribute_name` (two-stage string). - pub fn oakcommon_xml_reader_attribute_name( + ) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_read_element_text(reader, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_skip_current_element(reader: CHandle) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_skip_current_element(reader) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_count(reader, count) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_attribute_name( reader: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcommon_xml_reader_attribute_value` (two-stage string). - pub fn oakcommon_xml_reader_attribute_value( + ) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_name(reader, index, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_attribute_value( reader: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakcommon_xml_reader_has_error`. - pub fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int; - /// `oakcommon_xml_writer_init` — fresh writer. - pub fn oakcommon_xml_writer_init() -> CHandle; - /// `oakcommon_xml_writer_free` — NULL/empty no-op. - pub fn oakcommon_xml_writer_free(writer: *mut CHandle); - /// `oakcommon_xml_writer_write_start_element`. - pub fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int; - /// `oakcommon_xml_writer_write_attribute`. - pub fn oakcommon_xml_writer_write_attribute( + ) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_value(reader, index, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_has_error(reader, has_error) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_init() -> CHandle { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_init() } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_free(writer: *mut CHandle) { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_free(writer) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_start_element(writer, name) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_write_attribute( writer: CHandle, name: *const c_char, value: *const c_char, - ) -> c_int; - /// `oakcommon_xml_writer_write_characters`. - pub fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int; - /// `oakcommon_xml_writer_write_text_element`. - pub fn oakcommon_xml_writer_write_text_element( + ) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_attribute(writer, name, value) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_characters(writer, text) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_write_text_element( writer: CHandle, name: *const c_char, text: *const c_char, - ) -> c_int; - /// `oakcommon_xml_writer_write_end_element`. - pub fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int; - /// `oakcommon_xml_writer_write_end_document`. - pub fn oakcommon_xml_writer_write_end_document(writer: CHandle) -> c_int; - /// `oakcommon_xml_writer_output` (two-stage string). - pub fn oakcommon_xml_writer_output(writer: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - - // ---- decibel helpers ------------------------------------------------- - /// `oakcommon_decibel_from_linear` — linear amplitude to decibels. - pub fn oakcommon_decibel_from_linear(linear: f64, out_db: *mut f64) -> c_int; - /// `oakcommon_decibel_to_linear` — decibels to linear amplitude. - pub fn oakcommon_decibel_to_linear(db: f64, out_linear: *mut f64) -> c_int; - /// `oakcommon_decibel_from_logarithmic` — slider position to decibels. - pub fn oakcommon_decibel_from_logarithmic(logarithmic: f64, out_db: *mut f64) -> c_int; - /// `oakcommon_decibel_to_logarithmic` — decibels to slider position. - pub fn oakcommon_decibel_to_logarithmic(db: f64, out_logarithmic: *mut f64) -> c_int; - /// `oakcommon_decibel_linear_to_logarithmic`. - pub fn oakcommon_decibel_linear_to_logarithmic(linear: f64, out_logarithmic: *mut f64) -> c_int; - /// `oakcommon_decibel_logarithmic_to_linear`. - pub fn oakcommon_decibel_logarithmic_to_linear(logarithmic: f64, out_linear: *mut f64) -> c_int; + ) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_text_element(writer, name, text) } } + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_end_element(writer) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_write_end_document(writer: CHandle) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_end_document(writer) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_xml_writer_output(writer: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_output(writer, buf, buf_size) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_decibel_from_linear(linear: f64, out_db: *mut f64) -> c_int { + unsafe { oakcommon::ffi::misc::oakcommon_decibel_from_linear(linear, out_db) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_decibel_to_linear(db: f64, out_linear: *mut f64) -> c_int { + unsafe { oakcommon::ffi::misc::oakcommon_decibel_to_linear(db, out_linear) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_decibel_from_logarithmic(logarithmic: f64, out_db: *mut f64) -> c_int { + unsafe { oakcommon::ffi::misc::oakcommon_decibel_from_logarithmic(logarithmic, out_db) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_decibel_to_logarithmic(db: f64, out_logarithmic: *mut f64) -> c_int { + unsafe { oakcommon::ffi::misc::oakcommon_decibel_to_logarithmic(db, out_logarithmic) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_decibel_linear_to_logarithmic(linear: f64, out_logarithmic: *mut f64) -> c_int { + unsafe { oakcommon::ffi::misc::oakcommon_decibel_linear_to_logarithmic(linear, out_logarithmic) } +} + +/// Direct call into the `oakcommon` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakcommon_decibel_logarithmic_to_linear(logarithmic: f64, out_linear: *mut f64) -> c_int { + unsafe { oakcommon::ffi::misc::oakcommon_decibel_logarithmic_to_linear(logarithmic, out_linear) } +} + diff --git a/src/engine/rust/src/bridge/node.rs b/src/engine/rust/src/bridge/node.rs index 43b1d626d..fd4b5907b 100644 --- a/src/engine/rust/src/bridge/node.rs +++ b/src/engine/rust/src/bridge/node.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oaknode C ABI bridge: direct Rust calls into the `oaknode` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oaknode`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oaknode C ABI imports, mirroring the oaknode crate's exports //! (`src/node/rust/src/ffi.rs`; headers `include/node/*.h`). //! @@ -31,227 +58,569 @@ use crate::handle::CHandle; // (defined in [`crate::node`]). The facade hands the engine's // `oak_node_value` straight to the module (the two structs are // layout-identical). -extern "C" { - // ---- include/node/project.h -------------------------------------------- - /// `oaknode_project_init` — new project, refcount 1. - pub fn oaknode_project_init() -> CHandle; - /// `oaknode_project_free` — NULL/empty no-op; clears `project->ctx`. - pub fn oaknode_project_free(project: *mut CHandle); - /// `oaknode_project_initialize` — create the root folder. - pub fn oaknode_project_initialize(project: CHandle) -> c_int; - /// `oaknode_project_clear` — destroy all nodes, keep the shell. - pub fn oaknode_project_clear(project: CHandle) -> c_int; - /// `oaknode_project_root` — borrowed root folder handle. - pub fn oaknode_project_root(project: CHandle) -> CHandle; - /// `oaknode_project_name` (two-stage string). - pub fn oaknode_project_name(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_project_filename` (two-stage string). - pub fn oaknode_project_filename(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_project_pretty_filename` (two-stage string). - pub fn oaknode_project_pretty_filename(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_project_set_filename`. - pub fn oaknode_project_set_filename(project: CHandle, filename: *const c_char) -> c_int; - /// `oaknode_project_is_modified`. - pub fn oaknode_project_is_modified(project: CHandle) -> c_int; - /// `oaknode_project_set_modified`. - pub fn oaknode_project_set_modified(project: CHandle, modified: c_int) -> c_int; - /// `oaknode_project_is_new`. - pub fn oaknode_project_is_new(project: CHandle) -> c_int; - /// `oaknode_project_cache_path` (two-stage string). - pub fn oaknode_project_cache_path(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_project_copy_settings`. - pub fn oaknode_project_copy_settings(dst: CHandle, src: CHandle) -> c_int; - /// `oaknode_project_get_cache_location_setting`. - pub fn oaknode_project_get_cache_location_setting(project: CHandle) -> c_int; - /// `oaknode_project_set_cache_location_setting`. - pub fn oaknode_project_set_cache_location_setting(project: CHandle, setting: c_int) -> c_int; - /// `oaknode_project_get_custom_cache_path` (two-stage string). - pub fn oaknode_project_get_custom_cache_path(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_project_set_custom_cache_path`. - pub fn oaknode_project_set_custom_cache_path(project: CHandle, path: *const c_char) -> c_int; - /// `oaknode_project_get_uuid` (two-stage string). - pub fn oaknode_project_get_uuid(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_project_add_node` — graph takes the node's lifetime. - pub fn oaknode_project_add_node(project: CHandle, node: CHandle) -> c_int; - /// `oaknode_project_remove_node` — detach without deleting. - pub fn oaknode_project_remove_node(project: CHandle, node: CHandle) -> c_int; - /// `oaknode_project_node_count`. - pub fn oaknode_project_node_count(project: CHandle) -> c_int; - /// `oaknode_project_node_at` — borrowed handle at index. - pub fn oaknode_project_node_at(project: CHandle, index: c_int) -> CHandle; - // ---- include/node/node.h ------------------------------------------------ - /// `oaknode_debug_alive_count`. - pub fn oaknode_debug_alive_count() -> c_int; - /// `oaknode_node_get_id` (two-stage string). - pub fn oaknode_node_get_id(node: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_node_get_name` (two-stage string). - pub fn oaknode_node_get_name(node: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_node_get_label` (two-stage string). - pub fn oaknode_node_get_label(node: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_node_set_label` — live. - pub fn oaknode_node_set_label(node: CHandle, label: *const c_char) -> c_int; - /// `oaknode_node_set_label_undoable`. - pub fn oaknode_node_set_label_undoable(node: CHandle, label: *const c_char, out_command: *mut CHandle) -> c_int; - /// `oaknode_node_get_override_color`. - pub fn oaknode_node_get_override_color(node: CHandle, out_value: *mut c_int) -> c_int; - /// `oaknode_node_set_override_color` — live. - pub fn oaknode_node_set_override_color(node: CHandle, index: c_int) -> c_int; - /// `oaknode_node_set_override_color_undoable`. - pub fn oaknode_node_set_override_color_undoable(node: CHandle, index: c_int, out_command: *mut CHandle) -> c_int; - /// `oaknode_node_is_enabled`. - pub fn oaknode_node_is_enabled(node: CHandle, out_value: *mut c_int) -> c_int; - /// `oaknode_node_set_enabled` — live. - pub fn oaknode_node_set_enabled(node: CHandle, enabled: c_int) -> c_int; - /// `oaknode_node_set_enabled_undoable`. - pub fn oaknode_node_set_enabled_undoable(node: CHandle, enabled: c_int, out_command: *mut CHandle) -> c_int; - /// `oaknode_node_input_count`. - pub fn oaknode_node_input_count(node: CHandle, out_count: *mut c_int) -> c_int; - /// `oaknode_node_input_id` (two-stage string). - pub fn oaknode_node_input_id(node: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_node_input_get_type`. - pub fn oaknode_node_input_get_type(node: CHandle, input_id: *const c_char, out_type: *mut c_int) -> c_int; - /// `oaknode_node_input_is_connected`. - pub fn oaknode_node_input_is_connected(node: CHandle, input_id: *const c_char, out_value: *mut c_int) -> c_int; - /// `oaknode_node_input_is_connectable`. - pub fn oaknode_node_input_is_connectable(node: CHandle, input_id: *const c_char, out_value: *mut c_int) -> c_int; - /// `oaknode_node_get_input_name` (two-stage string). - pub fn oaknode_node_get_input_name(node: CHandle, input_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_node_input_get_connected_node` — borrowed handle out. - pub fn oaknode_node_input_get_connected_node(node: CHandle, input_id: *const c_char, out_node: *mut CHandle) -> c_int; - /// `oaknode_node_get_input` — POD value out. - pub fn oaknode_node_get_input( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_init() -> CHandle { + unsafe { oaknode::ffi::project::oaknode_project_init() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_free(project: *mut CHandle) { + unsafe { oaknode::ffi::project::oaknode_project_free(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_initialize(project: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_initialize(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_clear(project: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_clear(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_root(project: CHandle) -> CHandle { + unsafe { oaknode::ffi::project::oaknode_project_root(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_name(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_name(project, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_filename(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_filename(project, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_pretty_filename(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_pretty_filename(project, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_set_filename(project: CHandle, filename: *const c_char) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_set_filename(project, filename) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_is_modified(project: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_is_modified(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_set_modified(project: CHandle, modified: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_set_modified(project, modified) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_is_new(project: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_is_new(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_cache_path(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_cache_path(project, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_copy_settings(dst: CHandle, src: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_copy_settings(dst, src) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_get_cache_location_setting(project: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_get_cache_location_setting(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_set_cache_location_setting(project: CHandle, setting: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_set_cache_location_setting(project, setting) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_get_custom_cache_path(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_get_custom_cache_path(project, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_set_custom_cache_path(project: CHandle, path: *const c_char) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_set_custom_cache_path(project, path) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_get_uuid(project: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_get_uuid(project, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_add_node(project: CHandle, node: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_add_node(project, node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_remove_node(project: CHandle, node: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_remove_node(project, node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_node_count(project: CHandle) -> c_int { + unsafe { oaknode::ffi::project::oaknode_project_node_count(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_project_node_at(project: CHandle, index: c_int) -> CHandle { + unsafe { oaknode::ffi::project::oaknode_project_node_at(project, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_debug_alive_count() -> c_int { + unsafe { oaknode::ffi::node::oaknode_debug_alive_count() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_id(node: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_id(node, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_name(node: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_name(node, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_label(node: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_label(node, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_label(node: CHandle, label: *const c_char) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_label(node, label) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_label_undoable(node: CHandle, label: *const c_char, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_label_undoable(node, label, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_override_color(node: CHandle, out_value: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_override_color(node, out_value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_override_color(node: CHandle, index: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_override_color(node, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_override_color_undoable(node: CHandle, index: c_int, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_override_color_undoable(node, index, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_is_enabled(node: CHandle, out_value: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_is_enabled(node, out_value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_enabled(node: CHandle, enabled: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_enabled(node, enabled) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_enabled_undoable(node: CHandle, enabled: c_int, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_enabled_undoable(node, enabled, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_count(node: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_count(node, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_id(node: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_id(node, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_get_type(node: CHandle, input_id: *const c_char, out_type: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_get_type(node, input_id, out_type) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_is_connected(node: CHandle, input_id: *const c_char, out_value: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_is_connected(node, input_id, out_value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_is_connectable(node: CHandle, input_id: *const c_char, out_value: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_is_connectable(node, input_id, out_value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_input_name(node: CHandle, input_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_input_name(node, input_id, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_get_connected_node(node: CHandle, input_id: *const c_char, out_node: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_get_connected_node(node, input_id, out_node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_input( node: CHandle, input_id: *const c_char, out: *mut crate::node::OakNodeValue, - ) -> c_int; - /// `oaknode_node_set_input` — live. - pub fn oaknode_node_set_input(node: CHandle, input_id: *const c_char, v: *const crate::node::OakNodeValue) -> c_int; - /// `oaknode_node_set_input_undoable`. - pub fn oaknode_node_set_input_undoable( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_input(node, input_id, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_input(node: CHandle, input_id: *const c_char, v: *const crate::node::OakNodeValue) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_input(node, input_id, v) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_input_undoable( node: CHandle, input_id: *const c_char, v: *const crate::node::OakNodeValue, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_node_get_input_string` (two-stage string). - pub fn oaknode_node_get_input_string(node: CHandle, input_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_node_set_input_string` — live. - pub fn oaknode_node_set_input_string(node: CHandle, input_id: *const c_char, value: *const c_char) -> c_int; - /// `oaknode_node_set_input_string_undoable`. - pub fn oaknode_node_set_input_string_undoable( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_input_undoable(node, input_id, v, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_input_string(node: CHandle, input_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_input_string(node, input_id, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_input_string(node: CHandle, input_id: *const c_char, value: *const c_char) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_input_string(node, input_id, value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_input_string_undoable( node: CHandle, input_id: *const c_char, value: *const c_char, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_node_connect` — live, element -1. - pub fn oaknode_node_connect(output_node: CHandle, input_node: CHandle, input_id: *const c_char) -> c_int; - /// `oaknode_node_connect_undoable`. - pub fn oaknode_node_connect_undoable( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_input_string_undoable(node, input_id, value, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_connect(output_node: CHandle, input_node: CHandle, input_id: *const c_char) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_connect(output_node, input_node, input_id) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_connect_undoable( output_node: CHandle, input_node: CHandle, input_id: *const c_char, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_node_disconnect` — live, element -1. - pub fn oaknode_node_disconnect(input_node: CHandle, input_id: *const c_char) -> c_int; - /// `oaknode_node_disconnect_undoable`. - pub fn oaknode_node_disconnect_undoable(input_node: CHandle, input_id: *const c_char, out_command: *mut CHandle) -> c_int; - /// `oaknode_node_output_connection_count`. - pub fn oaknode_node_output_connection_count(node: CHandle, out_count: *mut c_int) -> c_int; - /// `oaknode_node_output_connection_node_at` — borrowed handle out. - pub fn oaknode_node_output_connection_node_at(node: CHandle, index: c_int, out_node: *mut CHandle) -> c_int; - /// `oaknode_node_output_connection_input_id_at` (two-stage string). - pub fn oaknode_node_output_connection_input_id_at( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_connect_undoable(output_node, input_node, input_id, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_disconnect(input_node: CHandle, input_id: *const c_char) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_disconnect(input_node, input_id) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_disconnect_undoable(input_node: CHandle, input_id: *const c_char, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_disconnect_undoable(input_node, input_id, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_output_connection_count(node: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_output_connection_count(node, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_output_connection_node_at(node: CHandle, index: c_int, out_node: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_output_connection_node_at(node, index, out_node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_output_connection_input_id_at( node: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oaknode_node_output_connection_element_at`. - pub fn oaknode_node_output_connection_element_at(node: CHandle, index: c_int, out_element: *mut c_int) -> c_int; - /// `oaknode_node_link` — live; `out_linked` may be NULL. - pub fn oaknode_node_link(a: CHandle, b: CHandle, out_linked: *mut c_int) -> c_int; - /// `oaknode_node_unlink` — live; `out_unlinked` may be NULL. - pub fn oaknode_node_unlink(a: CHandle, b: CHandle, out_unlinked: *mut c_int) -> c_int; - /// `oaknode_node_link_undoable` — `link` != 0 links, 0 unlinks. - pub fn oaknode_node_link_undoable(a: CHandle, b: CHandle, link: c_int, out_command: *mut CHandle) -> c_int; - /// `oaknode_node_are_linked`. - pub fn oaknode_node_are_linked(a: CHandle, b: CHandle, out_value: *mut c_int) -> c_int; - /// `oaknode_node_link_count`. - pub fn oaknode_node_link_count(node: CHandle, out_count: *mut c_int) -> c_int; - /// `oaknode_node_link_at` — borrowed handle out. - pub fn oaknode_node_link_at(node: CHandle, index: c_int, out_node: *mut CHandle) -> c_int; - /// `oaknode_node_context_count`. - pub fn oaknode_node_context_count(node: CHandle, out_count: *mut c_int) -> c_int; - /// `oaknode_node_context_node_at` — borrowed handle out. - pub fn oaknode_node_context_node_at(node: CHandle, index: c_int, out_node: *mut CHandle) -> c_int; - /// `oaknode_node_get_context_position` — any out pointer may be NULL. - pub fn oaknode_node_get_context_position( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_output_connection_input_id_at(node, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_output_connection_element_at(node: CHandle, index: c_int, out_element: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_output_connection_element_at(node, index, out_element) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_link(a: CHandle, b: CHandle, out_linked: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_link(a, b, out_linked) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_unlink(a: CHandle, b: CHandle, out_unlinked: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_unlink(a, b, out_unlinked) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_link_undoable(a: CHandle, b: CHandle, link: c_int, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_link_undoable(a, b, link, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_are_linked(a: CHandle, b: CHandle, out_value: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_are_linked(a, b, out_value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_link_count(node: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_link_count(node, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_link_at(node: CHandle, index: c_int, out_node: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_link_at(node, index, out_node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_context_count(node: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_context_count(node, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_context_node_at(node: CHandle, index: c_int, out_node: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_context_node_at(node, index, out_node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_context_position( node: CHandle, context: CHandle, out_x: *mut f64, out_y: *mut f64, out_expanded: *mut c_int, - ) -> c_int; - /// `oaknode_node_set_context_position` — live. - pub fn oaknode_node_set_context_position(node: CHandle, context: CHandle, x: f64, y: f64, expanded: c_int) -> c_int; - /// `oaknode_node_set_context_position_undoable`. - pub fn oaknode_node_set_context_position_undoable( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_context_position(node, context, out_x, out_y, out_expanded) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_context_position(node: CHandle, context: CHandle, x: f64, y: f64, expanded: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_context_position(node, context, x, y, expanded) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_context_position_undoable( node: CHandle, context: CHandle, x: f64, y: f64, expanded: c_int, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_node_remove_from_context` — live. - pub fn oaknode_node_remove_from_context(node: CHandle, context: CHandle) -> c_int; - /// `oaknode_node_create_copy` — standalone copy, refcount 1. - pub fn oaknode_node_create_copy(node: CHandle) -> CHandle; - /// `oaknode_node_copy_in_graph` — copy + MultiUndoCommand out. - pub fn oaknode_node_copy_in_graph(node: CHandle, out_command: *mut CHandle) -> CHandle; - /// `oaknode_node_get_project` — borrowed project handle out. - pub fn oaknode_node_get_project(node: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_node_input_array_insert` — live. - pub fn oaknode_node_input_array_insert(node: CHandle, input_id: *const c_char, index: c_int) -> c_int; - /// `oaknode_node_input_array_remove` — live. - pub fn oaknode_node_input_array_remove(node: CHandle, input_id: *const c_char, index: c_int) -> c_int; - /// `oaknode_node_connect_element` — element-aware connect. - pub fn oaknode_node_connect_element(output_node: CHandle, input_node: CHandle, input_id: *const c_char, element: c_int) -> c_int; - /// `oaknode_node_disconnect_element` — element-aware disconnect. - pub fn oaknode_node_disconnect_element(input_node: CHandle, input_id: *const c_char, element: c_int) -> c_int; - /// `oaknode_command_create_add_node` — owned `NodeAddCommand`. - pub fn oaknode_command_create_add_node(graph: CHandle, node: CHandle) -> CHandle; - /// `oaknode_command_create_set_position_recursive` — owned command. - pub fn oaknode_command_create_set_position_recursive(node: CHandle, context: CHandle, x: f64, y: f64) -> CHandle; - /// `oaknode_node_get_markers` — addref'd oaktimeline list handle out. - pub fn oaknode_node_get_markers(node: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_node_get_work_area` — addref'd oaktimeline workarea handle out. - pub fn oaknode_node_get_work_area(node: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_node_get_video_frame_cache` — addref'd oakrender cache handle out. - pub fn oaknode_node_get_video_frame_cache(node: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_node_copy_inputs` — `include_connections` != 0 also copies edges. - pub fn oaknode_node_copy_inputs(dst: CHandle, src: CHandle, include_connections: c_int) -> c_int; - /// `oaknode_node_set_value_hint_track` — single texture type hint. - pub fn oaknode_node_set_value_hint_track(node: CHandle, input_id: *const c_char, track_type: c_int, track_index: c_int) -> c_int; - /// `oaknode_viewer_set_video_params` — `params` is an oakcommon handle. - pub fn oaknode_viewer_set_video_params(viewer: CHandle, params: *const CHandle) -> c_int; - /// `oaknode_viewer_set_audio_params` — `params` is a borrowed oakcore handle. - pub fn oaknode_viewer_set_audio_params(viewer: CHandle, params: *const c_void) -> c_int; - /// `oaknode_node_find_input_footage` — borrowed footage handle out. - pub fn oaknode_node_find_input_footage(node: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_node_get_input_at_time` — rational seconds. - pub fn oaknode_node_get_input_at_time( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_context_position_undoable(node, context, x, y, expanded, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_remove_from_context(node: CHandle, context: CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_remove_from_context(node, context) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_create_copy(node: CHandle) -> CHandle { + unsafe { oaknode::ffi::node::oaknode_node_create_copy(node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_copy_in_graph(node: CHandle, out_command: *mut CHandle) -> CHandle { + unsafe { oaknode::ffi::node::oaknode_node_copy_in_graph(node, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_project(node: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_project(node, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_array_insert(node: CHandle, input_id: *const c_char, index: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_array_insert(node, input_id, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_input_array_remove(node: CHandle, input_id: *const c_char, index: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_input_array_remove(node, input_id, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_connect_element(output_node: CHandle, input_node: CHandle, input_id: *const c_char, element: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_connect_element(output_node, input_node, input_id, element) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_disconnect_element(input_node: CHandle, input_id: *const c_char, element: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_disconnect_element(input_node, input_id, element) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_command_create_add_node(graph: CHandle, node: CHandle) -> CHandle { + unsafe { oaknode::ffi::node::oaknode_command_create_add_node(graph, node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_command_create_set_position_recursive(node: CHandle, context: CHandle, x: f64, y: f64) -> CHandle { + unsafe { oaknode::ffi::node::oaknode_command_create_set_position_recursive(node, context, x, y) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_markers(node: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_markers(node, out as *mut std::ffi::c_void) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_work_area(node: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_work_area(node, out as *mut std::ffi::c_void) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_video_frame_cache(node: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_video_frame_cache(node, out as *mut std::ffi::c_void) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_copy_inputs(dst: CHandle, src: CHandle, include_connections: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_copy_inputs(dst, src, include_connections) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_value_hint_track(node: CHandle, input_id: *const c_char, track_type: c_int, track_index: c_int) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_value_hint_track(node, input_id, track_type, track_index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_viewer_set_video_params(viewer: CHandle, params: *const CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_viewer_set_video_params(viewer, params as *const std::ffi::c_void) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_viewer_set_audio_params(viewer: CHandle, params: *const c_void) -> c_int { + unsafe { oaknode::ffi::node::oaknode_viewer_set_audio_params(viewer, params) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_find_input_footage(node: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_find_input_footage(node, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_get_input_at_time( node: CHandle, input_id: *const c_char, time_num: i64, time_den: i64, out: *mut crate::node::OakNodeValue, - ) -> c_int; - /// `oaknode_node_set_input_at_time_undoable` — rational seconds. - pub fn oaknode_node_set_input_at_time_undoable( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_get_input_at_time(node, input_id, time_num, time_den, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_input_at_time_undoable( node: CHandle, input_id: *const c_char, time_num: i64, @@ -259,11 +628,19 @@ extern "C" { v: *const crate::node::OakNodeValue, track: c_int, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_node_identity` — opaque identity int. - pub fn oaknode_node_identity(node: CHandle) -> usize; - /// `oaknode_node_set_input_at_time_into` — batch into a multi command. - pub fn oaknode_node_set_input_at_time_into( + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_input_at_time_undoable(node, input_id, time_num, time_den, v, track, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_identity(node: CHandle) -> usize { + unsafe { oaknode::ffi::node::oaknode_node_identity(node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_set_input_at_time_into( node: CHandle, input_id: *const c_char, time_num: i64, @@ -271,154 +648,370 @@ extern "C" { v: *const crate::node::OakNodeValue, track: c_int, multi_command: CHandle, - ) -> c_int; - /// `oaknode_command_create_remove_node` — owned remove+disconnect command. - pub fn oaknode_command_create_remove_node(node: CHandle) -> CHandle; - /// `oaknode_node_free` — NULL/empty no-op; clears `node->ctx`. - pub fn oaknode_node_free(node: *mut CHandle); + ) -> c_int { + unsafe { oaknode::ffi::node::oaknode_node_set_input_at_time_into(node, input_id, time_num, time_den, v, track, multi_command) } +} - // ---- include/node/factory.h --------------------------------------------- - /// `oaknode_factory_initialize`. - pub fn oaknode_factory_initialize() -> c_int; - /// `oaknode_factory_destroy`. - pub fn oaknode_factory_destroy(); - /// `oaknode_factory_id_count`. - pub fn oaknode_factory_id_count(out_count: *mut c_int) -> c_int; - /// `oaknode_factory_id_at` (two-stage string). - pub fn oaknode_factory_id_at(index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_factory_name_from_id` (two-stage string). - pub fn oaknode_factory_name_from_id(type_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_factory_create_from_id` — new node, refcount 1. - pub fn oaknode_factory_create_from_id(type_id: *const c_char) -> CHandle; - /// `oaknode_factory_node_at` — borrowed prototype handle out. - pub fn oaknode_factory_node_at(index: c_int, out_node: *mut CHandle) -> c_int; +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_command_create_remove_node(node: CHandle) -> CHandle { + unsafe { oaknode::ffi::node::oaknode_command_create_remove_node(node) } +} - // ---- include/node/folder.h ---------------------------------------------- - /// `oaknode_folder_create` — new folder node in the project. - pub fn oaknode_folder_create(project: CHandle) -> CHandle; - /// `oaknode_folder_child_count`. - pub fn oaknode_folder_child_count(folder: CHandle) -> c_int; - /// `oaknode_folder_child_at` — borrowed child handle. - pub fn oaknode_folder_child_at(folder: CHandle, index: c_int) -> CHandle; - /// `oaknode_folder_add_child` — live. - pub fn oaknode_folder_add_child(folder: CHandle, child: CHandle) -> c_int; - /// `oaknode_folder_as_node` — folder viewed as a node. - pub fn oaknode_folder_as_node(folder: CHandle) -> CHandle; - /// `oaknode_command_create_folder_add_child` — owned command. - pub fn oaknode_command_create_folder_add_child(folder: CHandle, child: CHandle) -> CHandle; - /// `oaknode_folder_remove_child` — live. - pub fn oaknode_folder_remove_child(folder: CHandle, child: CHandle) -> c_int; - /// `oaknode_folder_move_children` — move several nodes, one command. - pub fn oaknode_folder_move_children(nodes: *const CHandle, count: c_int, dest_folder: CHandle) -> c_int; - /// `oaknode_folder_has_child_recursive`. - pub fn oaknode_folder_has_child_recursive(folder: CHandle, child: CHandle) -> c_int; - /// `oaknode_folder_index_of_child`. - pub fn oaknode_folder_index_of_child(folder: CHandle, child: CHandle) -> c_int; - /// `oaknode_folder_parent_of` — the folder owning the node. - pub fn oaknode_folder_parent_of(node: CHandle) -> CHandle; +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_node_free(node: *mut CHandle) { + unsafe { oaknode::ffi::node::oaknode_node_free(node) } +} - // ---- include/node/footage.h --------------------------------------------- - /// `oaknode_footage_create` — new footage node in the project. - pub fn oaknode_footage_create(project: CHandle, filename: *const c_char) -> CHandle; - /// `oaknode_footage_as_node` — footage viewed as a node. - pub fn oaknode_footage_as_node(footage: CHandle) -> CHandle; - /// `oaknode_footage_filename` (two-stage string). - pub fn oaknode_footage_filename(footage: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_footage_set_filename` — triggers the reprobe cascade. - pub fn oaknode_footage_set_filename(footage: CHandle, filename: *const c_char) -> c_int; - /// `oaknode_footage_is_valid`. - pub fn oaknode_footage_is_valid(footage: CHandle) -> c_int; - /// `oaknode_footage_timestamp`. - pub fn oaknode_footage_timestamp(footage: CHandle, out_timestamp: *mut i64) -> c_int; - /// `oaknode_footage_set_timestamp`. - pub fn oaknode_footage_set_timestamp(footage: CHandle, timestamp: i64) -> c_int; - /// `oaknode_footage_decoder` (two-stage string). - pub fn oaknode_footage_decoder(footage: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_footage_total_stream_count`. - pub fn oaknode_footage_total_stream_count(footage: CHandle) -> c_int; - /// `oaknode_footage_video_stream_count`. - pub fn oaknode_footage_video_stream_count(footage: CHandle) -> c_int; - /// `oaknode_footage_audio_stream_count`. - pub fn oaknode_footage_audio_stream_count(footage: CHandle) -> c_int; - /// `oaknode_footage_subtitle_stream_count`. - pub fn oaknode_footage_subtitle_stream_count(footage: CHandle) -> c_int; - /// `oaknode_footage_duration` — rational seconds. - pub fn oaknode_footage_duration(footage: CHandle, out_numerator: *mut c_int, out_denominator: *mut c_int) -> c_int; - /// `oaknode_footage_proxy_enabled`. - pub fn oaknode_footage_proxy_enabled(footage: CHandle) -> c_int; - /// `oaknode_footage_set_proxy_enabled` — live. - pub fn oaknode_footage_set_proxy_enabled(footage: CHandle, enabled: c_int) -> c_int; - /// `oaknode_footage_proxy_path` (two-stage string). - pub fn oaknode_footage_proxy_path(footage: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_footage_proxy_state`. - pub fn oaknode_footage_proxy_state(footage: CHandle) -> c_int; - /// `oaknode_footage_set_proxy`. - pub fn oaknode_footage_set_proxy( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_factory_initialize() -> c_int { + unsafe { oaknode::ffi::factory::oaknode_factory_initialize() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_factory_destroy() { + unsafe { oaknode::ffi::factory::oaknode_factory_destroy() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_factory_id_count(out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::factory::oaknode_factory_id_count(out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_factory_id_at(index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::factory::oaknode_factory_id_at(index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_factory_name_from_id(type_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::factory::oaknode_factory_name_from_id(type_id, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_factory_create_from_id(type_id: *const c_char) -> CHandle { + unsafe { oaknode::ffi::factory::oaknode_factory_create_from_id(type_id) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_factory_node_at(index: c_int, out_node: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::factory::oaknode_factory_node_at(index, out_node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_create(project: CHandle) -> CHandle { + unsafe { oaknode::ffi::folder::oaknode_folder_create(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_child_count(folder: CHandle) -> c_int { + unsafe { oaknode::ffi::folder::oaknode_folder_child_count(folder) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_child_at(folder: CHandle, index: c_int) -> CHandle { + unsafe { oaknode::ffi::folder::oaknode_folder_child_at(folder, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_add_child(folder: CHandle, child: CHandle) -> c_int { + unsafe { oaknode::ffi::folder::oaknode_folder_add_child(folder, child) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_as_node(folder: CHandle) -> CHandle { + unsafe { oaknode::ffi::folder::oaknode_folder_as_node(folder) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_command_create_folder_add_child(folder: CHandle, child: CHandle) -> CHandle { + unsafe { oaknode::ffi::folder::oaknode_command_create_folder_add_child(folder, child) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_remove_child(folder: CHandle, child: CHandle) -> c_int { + unsafe { oaknode::ffi::folder::oaknode_folder_remove_child(folder, child) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_move_children(nodes: *const CHandle, count: c_int, dest_folder: CHandle) -> c_int { + unsafe { oaknode::ffi::folder::oaknode_folder_move_children(nodes, count, dest_folder) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_has_child_recursive(folder: CHandle, child: CHandle) -> c_int { + unsafe { oaknode::ffi::folder::oaknode_folder_has_child_recursive(folder, child) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_index_of_child(folder: CHandle, child: CHandle) -> c_int { + unsafe { oaknode::ffi::folder::oaknode_folder_index_of_child(folder, child) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_folder_parent_of(node: CHandle) -> CHandle { + unsafe { oaknode::ffi::folder::oaknode_folder_parent_of(node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_create(project: CHandle, filename: *const c_char) -> CHandle { + unsafe { oaknode::ffi::footage::oaknode_footage_create(project, filename) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_as_node(footage: CHandle) -> CHandle { + unsafe { oaknode::ffi::footage::oaknode_footage_as_node(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_filename(footage: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_filename(footage, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_set_filename(footage: CHandle, filename: *const c_char) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_set_filename(footage, filename) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_is_valid(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_is_valid(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_timestamp(footage: CHandle, out_timestamp: *mut i64) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_timestamp(footage, out_timestamp) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_set_timestamp(footage: CHandle, timestamp: i64) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_set_timestamp(footage, timestamp) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_decoder(footage: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_decoder(footage, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_total_stream_count(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_total_stream_count(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_video_stream_count(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_video_stream_count(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_audio_stream_count(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_audio_stream_count(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_subtitle_stream_count(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_subtitle_stream_count(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_duration(footage: CHandle, out_numerator: *mut c_int, out_denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_duration(footage, out_numerator, out_denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_proxy_enabled(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_proxy_enabled(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_set_proxy_enabled(footage: CHandle, enabled: c_int) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_set_proxy_enabled(footage, enabled) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_proxy_path(footage: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_proxy_path(footage, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_proxy_state(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_proxy_state(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_set_proxy( footage: CHandle, path: *const c_char, state: c_int, video_stream_index: c_int, preset_version: c_int, enabled: c_int, - ) -> c_int; - /// `oaknode_footage_clear_proxy`. - pub fn oaknode_footage_clear_proxy(footage: CHandle) -> c_int; - /// `oaknode_footage_get_video_params` — oakcommon handle out. - pub fn oaknode_footage_get_video_params(footage: CHandle, index: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_footage_set_video_params` — oakcommon handle in. - pub fn oaknode_footage_set_video_params(footage: CHandle, index: c_int, params: *const CHandle) -> c_int; - /// `oaknode_footage_get_video_length` — rational seconds. - pub fn oaknode_footage_get_video_length(footage: CHandle, out_num: *mut i64, out_den: *mut i64) -> c_int; - /// `oaknode_footage_set_cancel_atom`. - pub fn oaknode_footage_set_cancel_atom(footage: CHandle, atom: CHandle) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_set_proxy(footage, path, state, video_stream_index, preset_version, enabled) } +} - // ---- include/node/group.h ----------------------------------------------- - /// `oaknode_group_create` — detached group node, refcount 1. - pub fn oaknode_group_create() -> CHandle; - /// `oaknode_group_cast` — node viewed as a group. - pub fn oaknode_group_cast(node: CHandle) -> CHandle; - /// `oaknode_group_free` — NULL/empty no-op. - pub fn oaknode_group_free(group: *mut CHandle); - /// `oaknode_group_add_input_passthrough` — direct; id written two-stage. - pub fn oaknode_group_add_input_passthrough( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_clear_proxy(footage: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_clear_proxy(footage) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_get_video_params(footage: CHandle, index: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_get_video_params(footage, index, out as *mut std::ffi::c_void) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_set_video_params(footage: CHandle, index: c_int, params: *const CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_set_video_params(footage, index, params as *const std::ffi::c_void) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_get_video_length(footage: CHandle, out_num: *mut i64, out_den: *mut i64) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_get_video_length(footage, out_num, out_den) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_footage_set_cancel_atom(footage: CHandle, atom: CHandle) -> c_int { + unsafe { oaknode::ffi::footage::oaknode_footage_set_cancel_atom(footage, atom) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_create() -> CHandle { + unsafe { oaknode::ffi::group::oaknode_group_create() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_cast(node: CHandle) -> CHandle { + unsafe { oaknode::ffi::group::oaknode_group_cast(node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_free(group: *mut CHandle) { + unsafe { oaknode::ffi::group::oaknode_group_free(group) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_add_input_passthrough( group: CHandle, node: CHandle, input_id: *const c_char, element: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oaknode_group_add_input_passthrough_undoable`. - pub fn oaknode_group_add_input_passthrough_undoable( + ) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_add_input_passthrough(group, node, input_id, element, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_add_input_passthrough_undoable( group: CHandle, node: CHandle, input_id: *const c_char, element: c_int, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_group_remove_input_passthrough` — direct. - pub fn oaknode_group_remove_input_passthrough(group: CHandle, node: CHandle, input_id: *const c_char, element: c_int) -> c_int; - /// `oaknode_group_passthrough_count`. - pub fn oaknode_group_passthrough_count(group: CHandle, out_count: *mut c_int) -> c_int; - /// `oaknode_group_passthrough_id_at` (two-stage string). - pub fn oaknode_group_passthrough_id_at(group: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_group_passthrough_input_at` — node/input/element out. - pub fn oaknode_group_passthrough_input_at( + ) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_add_input_passthrough_undoable(group, node, input_id, element, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_remove_input_passthrough(group: CHandle, node: CHandle, input_id: *const c_char, element: c_int) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_remove_input_passthrough(group, node, input_id, element) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_passthrough_count(group: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_passthrough_count(group, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_passthrough_id_at(group: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_passthrough_id_at(group, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_passthrough_input_at( group: CHandle, index: c_int, out_node: *mut CHandle, buf: *mut c_char, buf_size: c_int, out_element: *mut c_int, - ) -> c_int; - /// `oaknode_group_get_output_passthrough`. - pub fn oaknode_group_get_output_passthrough(group: CHandle, out_node: *mut CHandle) -> c_int; - /// `oaknode_group_set_output_passthrough` — direct. - pub fn oaknode_group_set_output_passthrough(group: CHandle, node: CHandle) -> c_int; - /// `oaknode_group_set_output_passthrough_undoable`. - pub fn oaknode_group_set_output_passthrough_undoable(group: CHandle, node: CHandle, out_command: *mut CHandle) -> c_int; - /// `oaknode_group_resolve_input` — resolve a passthrough id. - pub fn oaknode_group_resolve_input( + ) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_passthrough_input_at(group, index, out_node, buf, buf_size, out_element) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_get_output_passthrough(group: CHandle, out_node: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_get_output_passthrough(group, out_node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_set_output_passthrough(group: CHandle, node: CHandle) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_set_output_passthrough(group, node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_set_output_passthrough_undoable(group: CHandle, node: CHandle, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_set_output_passthrough_undoable(group, node, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_group_resolve_input( node: CHandle, input_id: *const c_char, element: c_int, @@ -426,11 +1019,13 @@ extern "C" { buf: *mut c_char, buf_size: c_int, out_element: *mut c_int, - ) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::group::oaknode_group_resolve_input(node, input_id, element, out_node, buf, buf_size, out_element) } +} - // ---- include/node/keyframe.h -------------------------------------------- - /// `oaknode_keyframe_create` — detached keyframe, refcount 1. - pub fn oaknode_keyframe_create( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_create( time_num: i64, time_den: i64, value: *const crate::node::OakNodeValue, @@ -439,445 +1034,1151 @@ extern "C" { element: c_int, input_id: *const c_char, parent_or_null: CHandle, - ) -> CHandle; - /// `oaknode_keyframe_free` — NULL/empty no-op. - pub fn oaknode_keyframe_free(keyframe: *mut CHandle); - /// `oaknode_keyframe_get_time`. - pub fn oaknode_keyframe_get_time(keyframe: CHandle, out_num: *mut i64, out_den: *mut i64) -> c_int; - /// `oaknode_keyframe_set_time` — live. - pub fn oaknode_keyframe_set_time(keyframe: CHandle, time_num: i64, time_den: i64) -> c_int; - /// `oaknode_keyframe_set_time_undoable`. - pub fn oaknode_keyframe_set_time_undoable( + ) -> CHandle { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_create(time_num, time_den, value, type_, track, element, input_id, parent_or_null) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_free(keyframe: *mut CHandle) { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_free(keyframe) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_time(keyframe: CHandle, out_num: *mut i64, out_den: *mut i64) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_time(keyframe, out_num, out_den) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_time(keyframe: CHandle, time_num: i64, time_den: i64) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_time(keyframe, time_num, time_den) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_time_undoable( keyframe: CHandle, time_num: i64, time_den: i64, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_keyframe_get_value` — POD out. - pub fn oaknode_keyframe_get_value(keyframe: CHandle, out: *mut crate::node::OakNodeValue) -> c_int; - /// `oaknode_keyframe_set_value` — live. - pub fn oaknode_keyframe_set_value(keyframe: CHandle, v: *const crate::node::OakNodeValue) -> c_int; - /// `oaknode_keyframe_set_value_undoable`. - pub fn oaknode_keyframe_set_value_undoable( + ) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_time_undoable(keyframe, time_num, time_den, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_value(keyframe: CHandle, out: *mut crate::node::OakNodeValue) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_value(keyframe, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_value(keyframe: CHandle, v: *const crate::node::OakNodeValue) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_value(keyframe, v) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_value_undoable( keyframe: CHandle, v: *const crate::node::OakNodeValue, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_keyframe_get_value_string` (two-stage string). - pub fn oaknode_keyframe_get_value_string(keyframe: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_keyframe_set_value_string` — live. - pub fn oaknode_keyframe_set_value_string(keyframe: CHandle, value: *const c_char) -> c_int; - /// `oaknode_keyframe_set_value_string_undoable`. - pub fn oaknode_keyframe_set_value_string_undoable( + ) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_value_undoable(keyframe, v, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_value_string(keyframe: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_value_string(keyframe, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_value_string(keyframe: CHandle, value: *const c_char) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_value_string(keyframe, value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_value_string_undoable( keyframe: CHandle, value: *const c_char, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_keyframe_get_type`. - pub fn oaknode_keyframe_get_type(keyframe: CHandle, out_type: *mut c_int) -> c_int; - /// `oaknode_keyframe_set_type` — live. - pub fn oaknode_keyframe_set_type(keyframe: CHandle, type_: c_int) -> c_int; - /// `oaknode_keyframe_set_type_undoable`. - pub fn oaknode_keyframe_set_type_undoable(keyframe: CHandle, type_: c_int, out_command: *mut CHandle) -> c_int; - /// `oaknode_keyframe_get_bezier_control` — `handle` 0=in, 1=out. - pub fn oaknode_keyframe_get_bezier_control(keyframe: CHandle, handle: c_int, out_x: *mut f64, out_y: *mut f64) -> c_int; - /// `oaknode_keyframe_set_bezier_control` — live. - pub fn oaknode_keyframe_set_bezier_control(keyframe: CHandle, handle: c_int, x: f64, y: f64) -> c_int; - /// `oaknode_keyframe_set_bezier_control_undoable`. - pub fn oaknode_keyframe_set_bezier_control_undoable( + ) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_value_string_undoable(keyframe, value, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_type(keyframe: CHandle, out_type: *mut c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_type(keyframe, out_type) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_type(keyframe: CHandle, type_: c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_type(keyframe, type_) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_type_undoable(keyframe: CHandle, type_: c_int, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_type_undoable(keyframe, type_, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_bezier_control(keyframe: CHandle, handle: c_int, out_x: *mut f64, out_y: *mut f64) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_bezier_control(keyframe, handle, out_x, out_y) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_bezier_control(keyframe: CHandle, handle: c_int, x: f64, y: f64) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_bezier_control(keyframe, handle, x, y) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_set_bezier_control_undoable( keyframe: CHandle, handle: c_int, x: f64, y: f64, out_command: *mut CHandle, - ) -> c_int; - /// `oaknode_keyframe_get_track`. - pub fn oaknode_keyframe_get_track(keyframe: CHandle, out_track: *mut c_int) -> c_int; - /// `oaknode_keyframe_get_element`. - pub fn oaknode_keyframe_get_element(keyframe: CHandle, out_element: *mut c_int) -> c_int; - /// `oaknode_keyframe_get_input` (two-stage string). - pub fn oaknode_keyframe_get_input(keyframe: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_keyframe_get_parent` — borrowed node handle out. - pub fn oaknode_keyframe_get_parent(keyframe: CHandle, out_node: *mut CHandle) -> c_int; - /// `oaknode_keyframe_get_valid_bezier_control` — identity for non-bezier. - pub fn oaknode_keyframe_get_valid_bezier_control(keyframe: CHandle, handle: c_int, out_x: *mut f64, out_y: *mut f64) -> c_int; - /// `oaknode_keyframe_opposing_bezier_type`. - pub fn oaknode_keyframe_opposing_bezier_type(type_: c_int) -> c_int; - /// `oaknode_keyframe_compute_paste_value` — POD out. - pub fn oaknode_keyframe_compute_paste_value( + ) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_set_bezier_control_undoable(keyframe, handle, x, y, out_command) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_track(keyframe: CHandle, out_track: *mut c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_track(keyframe, out_track) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_element(keyframe: CHandle, out_element: *mut c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_element(keyframe, out_element) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_input(keyframe: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_input(keyframe, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_parent(keyframe: CHandle, out_node: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_parent(keyframe, out_node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_get_valid_bezier_control(keyframe: CHandle, handle: c_int, out_x: *mut f64, out_y: *mut f64) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_get_valid_bezier_control(keyframe, handle, out_x, out_y) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_opposing_bezier_type(type_: c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_opposing_bezier_type(type_) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_compute_paste_value( target_node: CHandle, keyframe: CHandle, out: *mut crate::node::OakNodeValue, - ) -> c_int; - /// `oaknode_keyframe_has_sibling_at_time` — relative to own track. - pub fn oaknode_keyframe_has_sibling_at_time(keyframe: CHandle, time_num: i64, time_den: i64, out_value: *mut c_int) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_compute_paste_value(target_node, keyframe, out) } +} - // ---- include/node/dragger.h --------------------------------------------- - /// `oaknode_dragger_create` — new dragger, refcount 1. - pub fn oaknode_dragger_create(node: CHandle, input_id: *const c_char, element: c_int, track: c_int) -> CHandle; - /// `oaknode_dragger_start` — rational time. - pub fn oaknode_dragger_start( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_keyframe_has_sibling_at_time(keyframe: CHandle, time_num: i64, time_den: i64, out_value: *mut c_int) -> c_int { + unsafe { oaknode::ffi::keyframe::oaknode_keyframe_has_sibling_at_time(keyframe, time_num, time_den, out_value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_dragger_create(node: CHandle, input_id: *const c_char, element: c_int, track: c_int) -> CHandle { + unsafe { oaknode::ffi::dragger::oaknode_dragger_create(node, input_id, element, track) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_dragger_start( dragger: CHandle, time_num: i64, time_den: i64, track: c_int, insert_on_all_tracks: c_int, - ) -> c_int; - /// `oaknode_dragger_drag` — live. - pub fn oaknode_dragger_drag(dragger: CHandle, value: *const crate::node::OakNodeValue) -> c_int; - /// `oaknode_dragger_end` — owned command out. - pub fn oaknode_dragger_end(dragger: CHandle, out_command: *mut CHandle) -> c_int; - /// `oaknode_dragger_is_started`. - pub fn oaknode_dragger_is_started(dragger: CHandle, out_started: *mut c_int) -> c_int; - /// `oaknode_dragger_free` — NULL/empty no-op. - pub fn oaknode_dragger_free(dragger: *mut CHandle); + ) -> c_int { + unsafe { oaknode::ffi::dragger::oaknode_dragger_start(dragger, time_num, time_den, track, insert_on_all_tracks) } +} - // ---- include/node/multicam.h -------------------------------------------- - /// `oaknode_multicam_input_current` — static string, never freed. - pub fn oaknode_multicam_input_current() -> *const c_char; - /// `oaknode_multicam_input_sources` — static string, never freed. - pub fn oaknode_multicam_input_sources() -> *const c_char; - /// `oaknode_multicam_input_sequence` — static string, never freed. - pub fn oaknode_multicam_input_sequence() -> *const c_char; - /// `oaknode_multicam_input_sequence_type` — static string, never freed. - pub fn oaknode_multicam_input_sequence_type() -> *const c_char; - /// `oaknode_multicam_get_source_count`. - pub fn oaknode_multicam_get_source_count(node: CHandle, out_count: *mut c_int) -> c_int; - /// `oaknode_multicam_get_rows_and_columns`. - pub fn oaknode_multicam_get_rows_and_columns(source_count: c_int, rows: *mut c_int, cols: *mut c_int) -> c_int; - /// `oaknode_multicam_index_to_row_cols`. - pub fn oaknode_multicam_index_to_row_cols(index: c_int, rows: c_int, cols: c_int, out_row: *mut c_int, out_col: *mut c_int) -> c_int; - /// `oaknode_multicam_rows_cols_to_index`. - pub fn oaknode_multicam_rows_cols_to_index(row: c_int, col: c_int, rows: c_int, cols: c_int) -> c_int; - /// `oaknode_multicam_get_current_source`. - pub fn oaknode_multicam_get_current_source(node: CHandle, out_source: *mut c_int) -> c_int; +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_dragger_drag(dragger: CHandle, value: *const crate::node::OakNodeValue) -> c_int { + unsafe { oaknode::ffi::dragger::oaknode_dragger_drag(dragger, value) } +} - // ---- include/node/sequence.h -------------------------------------------- - /// `oaknode_sequence_create` — detached sequence, refcount 1. - pub fn oaknode_sequence_create() -> CHandle; - /// `oaknode_sequence_free` — NULL/empty no-op. - pub fn oaknode_sequence_free(sequence: *mut CHandle); - /// `oaknode_sequence_set_default_parameters`. - pub fn oaknode_sequence_set_default_parameters(sequence: CHandle) -> c_int; - /// `oaknode_sequence_as_node` — sequence viewed as a node. - pub fn oaknode_sequence_as_node(sequence: CHandle) -> CHandle; - /// `oaknode_sequence_from_node` — node viewed as a sequence. - pub fn oaknode_sequence_from_node(node: CHandle) -> CHandle; - /// `oaknode_sequence_get_track_list` — borrowed track list out. - pub fn oaknode_sequence_get_track_list(sequence: CHandle, type_: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_sequence_get_track_count`. - pub fn oaknode_sequence_get_track_count(sequence: CHandle, type_: c_int, count: *mut c_int) -> c_int; - /// `oaknode_sequence_get_track_at` — borrowed track handle out. - pub fn oaknode_sequence_get_track_at(sequence: CHandle, type_: c_int, index: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_sequence_get_all_track_count`. - pub fn oaknode_sequence_get_all_track_count(sequence: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_sequence_get_all_track_at` — borrowed track handle out. - pub fn oaknode_sequence_get_all_track_at(sequence: CHandle, index: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_sequence_get_playhead` — rational seconds. - pub fn oaknode_sequence_get_playhead(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_sequence_set_playhead` — rational seconds. - pub fn oaknode_sequence_set_playhead(sequence: CHandle, numerator: c_int, denominator: c_int) -> c_int; - /// `oaknode_sequence_get_length` — rational seconds. - pub fn oaknode_sequence_get_length(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_sequence_get_video_length` — rational seconds. - pub fn oaknode_sequence_get_video_length(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_sequence_get_audio_length` — rational seconds. - pub fn oaknode_sequence_get_audio_length(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_sequence_verify_length`. - pub fn oaknode_sequence_verify_length(sequence: CHandle) -> c_int; - /// `oaknode_sequence_get_video_stream_count`. - pub fn oaknode_sequence_get_video_stream_count(sequence: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_sequence_get_audio_stream_count`. - pub fn oaknode_sequence_get_audio_stream_count(sequence: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_sequence_get_video_params` — oakcommon handle out. - pub fn oaknode_sequence_get_video_params(sequence: CHandle, index: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_sequence_set_video_params` — oakcommon handle by value. - pub fn oaknode_sequence_set_video_params(sequence: CHandle, index: c_int, params: CHandle) -> c_int; - /// `oaknode_sequence_get_audio_params` — borrowed oakcore handle out. - pub fn oaknode_sequence_get_audio_params(sequence: CHandle, index: c_int, out: *mut *mut c_void) -> c_int; - /// `oaknode_sequence_set_audio_params` — borrowed oakcore handle in. - pub fn oaknode_sequence_set_audio_params(sequence: CHandle, index: c_int, params: *const c_void) -> c_int; +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_dragger_end(dragger: CHandle, out_command: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::dragger::oaknode_dragger_end(dragger, out_command) } +} - // ---- include/node/track.h ----------------------------------------------- - /// `oaknode_track_as_node` — track viewed as a node. - pub fn oaknode_track_as_node(track: CHandle) -> CHandle; - /// `oaknode_track_create` — new track, refcount 1. - pub fn oaknode_track_create(type_: c_int) -> CHandle; - /// `oaknode_track_free` — NULL/empty no-op. - pub fn oaknode_track_free(track: *mut CHandle); - /// `oaknode_track_get_type`. - pub fn oaknode_track_get_type(track: CHandle, type_: *mut c_int) -> c_int; - /// `oaknode_track_set_type`. - pub fn oaknode_track_set_type(track: CHandle, type_: c_int) -> c_int; - /// `oaknode_track_get_height`. - pub fn oaknode_track_get_height(track: CHandle, height: *mut f64) -> c_int; - /// `oaknode_track_set_height`. - pub fn oaknode_track_set_height(track: CHandle, height: f64) -> c_int; - /// `oaknode_track_get_height_in_pixels`. - pub fn oaknode_track_get_height_in_pixels(track: CHandle, height: *mut c_int) -> c_int; - /// `oaknode_track_set_height_in_pixels`. - pub fn oaknode_track_set_height_in_pixels(track: CHandle, height: c_int) -> c_int; - /// `oaknode_track_get_default_height_in_pixels`. - pub fn oaknode_track_get_default_height_in_pixels() -> c_int; - /// `oaknode_track_get_minimum_height_in_pixels`. - pub fn oaknode_track_get_minimum_height_in_pixels() -> c_int; - /// `oaknode_track_get_index`. - pub fn oaknode_track_get_index(track: CHandle, index: *mut c_int) -> c_int; - /// `oaknode_track_set_index`. - pub fn oaknode_track_set_index(track: CHandle, index: c_int) -> c_int; - /// `oaknode_track_get_muted`. - pub fn oaknode_track_get_muted(track: CHandle, muted: *mut c_int) -> c_int; - /// `oaknode_track_set_muted`. - pub fn oaknode_track_set_muted(track: CHandle, muted: c_int) -> c_int; - /// `oaknode_track_get_locked`. - pub fn oaknode_track_get_locked(track: CHandle, locked: *mut c_int) -> c_int; - /// `oaknode_track_set_locked`. - pub fn oaknode_track_set_locked(track: CHandle, locked: c_int) -> c_int; - /// `oaknode_track_get_reference`. - pub fn oaknode_track_get_reference(track: CHandle, type_: *mut c_int, index: *mut c_int) -> c_int; - /// `oaknode_track_get_length` — rational seconds. - pub fn oaknode_track_get_length(track: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_track_get_sequence` — borrowed sequence handle out. - pub fn oaknode_track_get_sequence(track: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_track_get_block_count`. - pub fn oaknode_track_get_block_count(track: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_track_get_block_at` — borrowed block handle out. - pub fn oaknode_track_get_block_at(track: CHandle, index: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_track_append_block`. - pub fn oaknode_track_append_block(track: CHandle, block: CHandle) -> c_int; - /// `oaknode_track_prepend_block`. - pub fn oaknode_track_prepend_block(track: CHandle, block: CHandle) -> c_int; - /// `oaknode_track_insert_block_at_index`. - pub fn oaknode_track_insert_block_at_index(track: CHandle, block: CHandle, index: c_int) -> c_int; - /// `oaknode_track_insert_block_after`. - pub fn oaknode_track_insert_block_after(track: CHandle, block: CHandle, before: CHandle) -> c_int; - /// `oaknode_track_insert_block_before`. - pub fn oaknode_track_insert_block_before(track: CHandle, block: CHandle, after: CHandle) -> c_int; - /// `oaknode_track_ripple_remove_block`. - pub fn oaknode_track_ripple_remove_block(track: CHandle, block: CHandle) -> c_int; - /// `oaknode_track_replace_block`. - pub fn oaknode_track_replace_block(track: CHandle, old_block: CHandle, new_block: CHandle) -> c_int; - /// `oaknode_track_get_block_index`. - pub fn oaknode_track_get_block_index(track: CHandle, block: CHandle, index: *mut c_int) -> c_int; - /// `oaknode_track_get_block_containing_time` — rational seconds. - pub fn oaknode_track_get_block_containing_time(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_track_get_visible_block_at_time` — rational seconds. - pub fn oaknode_track_get_visible_block_at_time(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_track_is_range_free`. - pub fn oaknode_track_is_range_free( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_dragger_is_started(dragger: CHandle, out_started: *mut c_int) -> c_int { + unsafe { oaknode::ffi::dragger::oaknode_dragger_is_started(dragger, out_started) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_dragger_free(dragger: *mut CHandle) { + unsafe { oaknode::ffi::dragger::oaknode_dragger_free(dragger) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_input_current() -> *const c_char { + unsafe { oaknode::ffi::multicam::oaknode_multicam_input_current() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_input_sources() -> *const c_char { + unsafe { oaknode::ffi::multicam::oaknode_multicam_input_sources() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_input_sequence() -> *const c_char { + unsafe { oaknode::ffi::multicam::oaknode_multicam_input_sequence() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_input_sequence_type() -> *const c_char { + unsafe { oaknode::ffi::multicam::oaknode_multicam_input_sequence_type() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_get_source_count(node: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::multicam::oaknode_multicam_get_source_count(node, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_get_rows_and_columns(source_count: c_int, rows: *mut c_int, cols: *mut c_int) -> c_int { + unsafe { oaknode::ffi::multicam::oaknode_multicam_get_rows_and_columns(source_count, rows, cols) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_index_to_row_cols(index: c_int, rows: c_int, cols: c_int, out_row: *mut c_int, out_col: *mut c_int) -> c_int { + unsafe { oaknode::ffi::multicam::oaknode_multicam_index_to_row_cols(index, rows, cols, out_row, out_col) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_rows_cols_to_index(row: c_int, col: c_int, rows: c_int, cols: c_int) -> c_int { + unsafe { oaknode::ffi::multicam::oaknode_multicam_rows_cols_to_index(row, col, rows, cols) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_multicam_get_current_source(node: CHandle, out_source: *mut c_int) -> c_int { + unsafe { oaknode::ffi::multicam::oaknode_multicam_get_current_source(node, out_source) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_create() -> CHandle { + unsafe { oaknode::ffi::sequence::oaknode_sequence_create() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_free(sequence: *mut CHandle) { + unsafe { oaknode::ffi::sequence::oaknode_sequence_free(sequence) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_set_default_parameters(sequence: CHandle) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_set_default_parameters(sequence) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_as_node(sequence: CHandle) -> CHandle { + unsafe { oaknode::ffi::sequence::oaknode_sequence_as_node(sequence) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_from_node(node: CHandle) -> CHandle { + unsafe { oaknode::ffi::sequence::oaknode_sequence_from_node(node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_track_list(sequence: CHandle, type_: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_track_list(sequence, type_, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_track_count(sequence: CHandle, type_: c_int, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_track_count(sequence, type_, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_track_at(sequence: CHandle, type_: c_int, index: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_track_at(sequence, type_, index, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_all_track_count(sequence: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_all_track_count(sequence, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_all_track_at(sequence: CHandle, index: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_all_track_at(sequence, index, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_playhead(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_playhead(sequence, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_set_playhead(sequence: CHandle, numerator: c_int, denominator: c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_set_playhead(sequence, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_length(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_length(sequence, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_video_length(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_video_length(sequence, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_audio_length(sequence: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_audio_length(sequence, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_verify_length(sequence: CHandle) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_verify_length(sequence) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_video_stream_count(sequence: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_video_stream_count(sequence, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_audio_stream_count(sequence: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_audio_stream_count(sequence, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_video_params(sequence: CHandle, index: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_video_params(sequence, index, out as *mut std::ffi::c_void) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_set_video_params(sequence: CHandle, index: c_int, params: CHandle) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_set_video_params(sequence, index, params) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_get_audio_params(sequence: CHandle, index: c_int, out: *mut *mut c_void) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_get_audio_params(sequence, index, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_sequence_set_audio_params(sequence: CHandle, index: c_int, params: *const c_void) -> c_int { + unsafe { oaknode::ffi::sequence::oaknode_sequence_set_audio_params(sequence, index, params) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_as_node(track: CHandle) -> CHandle { + unsafe { oaknode::ffi::track::oaknode_track_as_node(track) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_create(type_: c_int) -> CHandle { + unsafe { oaknode::ffi::track::oaknode_track_create(type_) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_free(track: *mut CHandle) { + unsafe { oaknode::ffi::track::oaknode_track_free(track) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_type(track: CHandle, type_: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_type(track, type_) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_set_type(track: CHandle, type_: c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_set_type(track, type_) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_height(track: CHandle, height: *mut f64) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_height(track, height) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_set_height(track: CHandle, height: f64) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_set_height(track, height) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_height_in_pixels(track: CHandle, height: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_height_in_pixels(track, height) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_set_height_in_pixels(track: CHandle, height: c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_set_height_in_pixels(track, height) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_default_height_in_pixels() -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_default_height_in_pixels() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_minimum_height_in_pixels() -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_minimum_height_in_pixels() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_index(track: CHandle, index: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_index(track, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_set_index(track: CHandle, index: c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_set_index(track, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_muted(track: CHandle, muted: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_muted(track, muted) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_set_muted(track: CHandle, muted: c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_set_muted(track, muted) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_locked(track: CHandle, locked: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_locked(track, locked) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_set_locked(track: CHandle, locked: c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_set_locked(track, locked) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_reference(track: CHandle, type_: *mut c_int, index: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_reference(track, type_, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_length(track: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_length(track, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_sequence(track: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_sequence(track, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_block_count(track: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_block_count(track, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_block_at(track: CHandle, index: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_block_at(track, index, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_append_block(track: CHandle, block: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_append_block(track, block) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_prepend_block(track: CHandle, block: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_prepend_block(track, block) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_insert_block_at_index(track: CHandle, block: CHandle, index: c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_insert_block_at_index(track, block, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_insert_block_after(track: CHandle, block: CHandle, before: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_insert_block_after(track, block, before) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_insert_block_before(track: CHandle, block: CHandle, after: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_insert_block_before(track, block, after) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_ripple_remove_block(track: CHandle, block: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_ripple_remove_block(track, block) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_replace_block(track: CHandle, old_block: CHandle, new_block: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_replace_block(track, old_block, new_block) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_block_index(track: CHandle, block: CHandle, index: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_block_index(track, block, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_block_containing_time(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_block_containing_time(track, numerator, denominator, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_visible_block_at_time(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_visible_block_at_time(track, numerator, denominator, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_is_range_free( track: CHandle, in_num: c_int, in_den: c_int, out_num: c_int, out_den: c_int, is_free: *mut c_int, - ) -> c_int; - /// `oaknode_track_get_nearest_block_before_or_at`. - pub fn oaknode_track_get_nearest_block_before_or_at(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_track_get_nearest_block_after_or_at`. - pub fn oaknode_track_get_nearest_block_after_or_at(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_tracklist_get_sequence` — borrowed sequence handle out. - pub fn oaknode_tracklist_get_sequence(list: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_tracklist_get_track_input_id` (two-stage string). - pub fn oaknode_tracklist_get_track_input_id(list: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_tracklist_array_append`. - pub fn oaknode_tracklist_array_append(list: CHandle) -> c_int; - /// `oaknode_tracklist_array_remove_last`. - pub fn oaknode_tracklist_array_remove_last(list: CHandle) -> c_int; - /// `oaknode_tracklist_get_array_index_from_cache_index`. - pub fn oaknode_tracklist_get_array_index_from_cache_index(list: CHandle, cache_index: c_int, out_index: *mut c_int) -> c_int; - /// `oaknode_tracklist_get_type`. - pub fn oaknode_tracklist_get_type(list: CHandle, type_: *mut c_int) -> c_int; - /// `oaknode_tracklist_get_track_count`. - pub fn oaknode_tracklist_get_track_count(list: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_tracklist_get_track_at` — borrowed track handle out. - pub fn oaknode_tracklist_get_track_at(list: CHandle, index: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_tracklist_get_total_length` — rational seconds. - pub fn oaknode_tracklist_get_total_length(list: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_tracklist_get_array_size`. - pub fn oaknode_tracklist_get_array_size(list: CHandle, size: *mut c_int) -> c_int; - /// `oaknode_tracklist_add_track`. - pub fn oaknode_tracklist_add_track(list: CHandle, track: CHandle) -> c_int; - /// `oaknode_tracklist_remove_track`. - pub fn oaknode_tracklist_remove_track(list: CHandle, track: CHandle) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_is_range_free(track, in_num, in_den, out_num, out_den, is_free) } +} - // ---- include/node/block.h ----------------------------------------------- - /// `oaknode_block_clip_create` — new clip block, refcount 1. - pub fn oaknode_block_clip_create() -> CHandle; - /// `oaknode_block_gap_create` — new gap block, refcount 1. - pub fn oaknode_block_gap_create() -> CHandle; - /// `oaknode_block_transition_create` — new transition block, refcount 1. - pub fn oaknode_block_transition_create(kind: c_int) -> CHandle; - /// `oaknode_block_free` — NULL/empty no-op. - pub fn oaknode_block_free(block: *mut CHandle); - /// `oaknode_block_get_kind`. - pub fn oaknode_block_get_kind(block: CHandle, out_kind: *mut c_int) -> c_int; - /// `oaknode_block_as_node` — block viewed as a node. - pub fn oaknode_block_as_node(block: CHandle) -> CHandle; - /// `oaknode_block_from_node` — node viewed as a block. - pub fn oaknode_block_from_node(node: CHandle) -> CHandle; - /// `oaknode_block_get_in` — rational seconds. - pub fn oaknode_block_get_in(block: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_block_set_in` — rational seconds. - pub fn oaknode_block_set_in(block: CHandle, numerator: c_int, denominator: c_int) -> c_int; - /// `oaknode_block_get_out` — rational seconds. - pub fn oaknode_block_get_out(block: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_block_set_out` — rational seconds. - pub fn oaknode_block_set_out(block: CHandle, numerator: c_int, denominator: c_int) -> c_int; - /// `oaknode_block_get_length` — rational seconds. - pub fn oaknode_block_get_length(block: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_block_set_length_and_media_out`. - pub fn oaknode_block_set_length_and_media_out(block: CHandle, numerator: c_int, denominator: c_int) -> c_int; - /// `oaknode_block_set_length_and_media_in`. - pub fn oaknode_block_set_length_and_media_in(block: CHandle, numerator: c_int, denominator: c_int) -> c_int; - /// `oaknode_block_get_enabled`. - pub fn oaknode_block_get_enabled(block: CHandle, enabled: *mut c_int) -> c_int; - /// `oaknode_block_set_enabled`. - pub fn oaknode_block_set_enabled(block: CHandle, enabled: c_int) -> c_int; - /// `oaknode_block_get_previous` — borrowed block handle out. - pub fn oaknode_block_get_previous(block: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_block_get_next` — borrowed block handle out. - pub fn oaknode_block_get_next(block: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_block_get_track` — borrowed track handle out. - pub fn oaknode_block_get_track(block: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_block_link` — live. - pub fn oaknode_block_link(a: CHandle, b: CHandle) -> c_int; - /// `oaknode_block_unlink` — live. - pub fn oaknode_block_unlink(a: CHandle, b: CHandle) -> c_int; - /// `oaknode_block_are_linked`. - pub fn oaknode_block_are_linked(a: CHandle, b: CHandle, linked: *mut c_int) -> c_int; - /// `oaknode_block_get_link_count`. - pub fn oaknode_block_get_link_count(block: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_block_get_link_at` — borrowed block handle out. - pub fn oaknode_block_get_link_at(block: CHandle, index: c_int, out: *mut CHandle) -> c_int; - /// `oaknode_clip_get_media_in` — rational seconds. - pub fn oaknode_clip_get_media_in(clip: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_clip_set_media_in` — rational seconds. - pub fn oaknode_clip_set_media_in(clip: CHandle, numerator: c_int, denominator: c_int) -> c_int; - /// `oaknode_clip_get_speed`. - pub fn oaknode_clip_get_speed(clip: CHandle, speed: *mut f64) -> c_int; - /// `oaknode_clip_set_speed`. - pub fn oaknode_clip_set_speed(clip: CHandle, speed: f64) -> c_int; - /// `oaknode_clip_get_reverse`. - pub fn oaknode_clip_get_reverse(clip: CHandle, reverse: *mut c_int) -> c_int; - /// `oaknode_clip_set_reverse`. - pub fn oaknode_clip_set_reverse(clip: CHandle, reverse: c_int) -> c_int; - /// `oaknode_clip_get_maintain_audio_pitch`. - pub fn oaknode_clip_get_maintain_audio_pitch(clip: CHandle, maintain: *mut c_int) -> c_int; - /// `oaknode_clip_set_maintain_audio_pitch`. - pub fn oaknode_clip_set_maintain_audio_pitch(clip: CHandle, maintain: c_int) -> c_int; - /// `oaknode_clip_get_loop_mode`. - pub fn oaknode_clip_get_loop_mode(clip: CHandle, loop_mode: *mut c_int) -> c_int; - /// `oaknode_clip_set_loop_mode`. - pub fn oaknode_clip_set_loop_mode(clip: CHandle, loop_mode: c_int) -> c_int; - /// `oaknode_clip_get_track_type`. - pub fn oaknode_clip_get_track_type(clip: CHandle, type_: *mut c_int) -> c_int; - /// `oaknode_transition_get_in_offset` — rational seconds. - pub fn oaknode_transition_get_in_offset(transition: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_transition_get_out_offset` — rational seconds. - pub fn oaknode_transition_get_out_offset(transition: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_transition_get_offset_center` — rational seconds. - pub fn oaknode_transition_get_offset_center(transition: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int; - /// `oaknode_transition_set_offset_center`. - pub fn oaknode_transition_set_offset_center(transition: CHandle, numerator: c_int, denominator: c_int) -> c_int; - /// `oaknode_transition_set_offsets_and_length`. - pub fn oaknode_transition_set_offsets_and_length( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_nearest_block_before_or_at(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_nearest_block_before_or_at(track, numerator, denominator, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_track_get_nearest_block_after_or_at(track: CHandle, numerator: c_int, denominator: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_track_get_nearest_block_after_or_at(track, numerator, denominator, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_sequence(list: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_sequence(list, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_track_input_id(list: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_track_input_id(list, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_array_append(list: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_array_append(list) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_array_remove_last(list: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_array_remove_last(list) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_array_index_from_cache_index(list: CHandle, cache_index: c_int, out_index: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_array_index_from_cache_index(list, cache_index, out_index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_type(list: CHandle, type_: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_type(list, type_) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_track_count(list: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_track_count(list, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_track_at(list: CHandle, index: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_track_at(list, index, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_total_length(list: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_total_length(list, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_get_array_size(list: CHandle, size: *mut c_int) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_get_array_size(list, size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_add_track(list: CHandle, track: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_add_track(list, track) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_tracklist_remove_track(list: CHandle, track: CHandle) -> c_int { + unsafe { oaknode::ffi::track::oaknode_tracklist_remove_track(list, track) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_clip_create() -> CHandle { + unsafe { oaknode::ffi::block::oaknode_block_clip_create() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_gap_create() -> CHandle { + unsafe { oaknode::ffi::block::oaknode_block_gap_create() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_transition_create(kind: c_int) -> CHandle { + unsafe { oaknode::ffi::block::oaknode_block_transition_create(kind) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_free(block: *mut CHandle) { + unsafe { oaknode::ffi::block::oaknode_block_free(block) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_kind(block: CHandle, out_kind: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_kind(block, out_kind) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_as_node(block: CHandle) -> CHandle { + unsafe { oaknode::ffi::block::oaknode_block_as_node(block) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_from_node(node: CHandle) -> CHandle { + unsafe { oaknode::ffi::block::oaknode_block_from_node(node) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_in(block: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_in(block, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_set_in(block: CHandle, numerator: c_int, denominator: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_set_in(block, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_out(block: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_out(block, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_set_out(block: CHandle, numerator: c_int, denominator: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_set_out(block, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_length(block: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_length(block, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_set_length_and_media_out(block: CHandle, numerator: c_int, denominator: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_set_length_and_media_out(block, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_set_length_and_media_in(block: CHandle, numerator: c_int, denominator: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_set_length_and_media_in(block, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_enabled(block: CHandle, enabled: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_enabled(block, enabled) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_set_enabled(block: CHandle, enabled: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_set_enabled(block, enabled) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_previous(block: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_previous(block, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_next(block: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_next(block, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_track(block: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_track(block, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_link(a: CHandle, b: CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_link(a, b) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_unlink(a: CHandle, b: CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_unlink(a, b) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_are_linked(a: CHandle, b: CHandle, linked: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_are_linked(a, b, linked) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_link_count(block: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_link_count(block, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_block_get_link_at(block: CHandle, index: c_int, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_block_get_link_at(block, index, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_get_media_in(clip: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_get_media_in(clip, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_set_media_in(clip: CHandle, numerator: c_int, denominator: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_set_media_in(clip, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_get_speed(clip: CHandle, speed: *mut f64) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_get_speed(clip, speed) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_set_speed(clip: CHandle, speed: f64) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_set_speed(clip, speed) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_get_reverse(clip: CHandle, reverse: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_get_reverse(clip, reverse) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_set_reverse(clip: CHandle, reverse: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_set_reverse(clip, reverse) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_get_maintain_audio_pitch(clip: CHandle, maintain: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_get_maintain_audio_pitch(clip, maintain) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_set_maintain_audio_pitch(clip: CHandle, maintain: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_set_maintain_audio_pitch(clip, maintain) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_get_loop_mode(clip: CHandle, loop_mode: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_get_loop_mode(clip, loop_mode) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_set_loop_mode(clip: CHandle, loop_mode: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_set_loop_mode(clip, loop_mode) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_get_track_type(clip: CHandle, type_: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_get_track_type(clip, type_) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_get_in_offset(transition: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_get_in_offset(transition, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_get_out_offset(transition: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_get_out_offset(transition, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_get_offset_center(transition: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_get_offset_center(transition, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_set_offset_center(transition: CHandle, numerator: c_int, denominator: c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_set_offset_center(transition, numerator, denominator) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_set_offsets_and_length( transition: CHandle, in_num: c_int, in_den: c_int, out_num: c_int, out_den: c_int, - ) -> c_int; - /// `oaknode_transition_is_dual`. - pub fn oaknode_transition_is_dual(transition: CHandle, dual: *mut c_int) -> c_int; - /// `oaknode_transition_get_connected_out_block` — borrowed block handle out. - pub fn oaknode_transition_get_connected_out_block(transition: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_transition_get_connected_in_block` — borrowed block handle out. - pub fn oaknode_transition_get_connected_in_block(transition: CHandle, out: *mut CHandle) -> c_int; - /// `oaknode_clip_add_cache_passthrough_from`. - pub fn oaknode_clip_add_cache_passthrough_from(clip: CHandle, other: CHandle) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_set_offsets_and_length(transition, in_num, in_den, out_num, out_den) } +} - // ---- include/node/colormanager.h ---------------------------------------- - /// `oaknode_colormanager_init` — manager for a project, refcount 1. - pub fn oaknode_colormanager_init(project: CHandle) -> CHandle; - /// `oaknode_colormanager_free` — NULL/empty no-op. - pub fn oaknode_colormanager_free(manager: *mut CHandle); - /// `oaknode_colormanager_wrap_borrowed` — wrap a native manager pointer. - pub fn oaknode_colormanager_wrap_borrowed(native_manager: *mut c_void) -> CHandle; - /// `oaknode_colormanager_initialize`. - pub fn oaknode_colormanager_initialize(manager: CHandle) -> c_int; - /// `oaknode_colormanager_set_up_default_config`. - pub fn oaknode_colormanager_set_up_default_config() -> c_int; - /// `oaknode_colormanager_get_config_filename` (two-stage string). - pub fn oaknode_colormanager_get_config_filename(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_set_config_filename`. - pub fn oaknode_colormanager_set_config_filename(manager: CHandle, filename: *const c_char) -> c_int; - /// `oaknode_colormanager_update_config_from_filename`. - pub fn oaknode_colormanager_update_config_from_filename(manager: CHandle) -> c_int; - /// `oaknode_colormanager_get_default_input_color_space` (two-stage string). - pub fn oaknode_colormanager_get_default_input_color_space(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_set_default_input_color_space`. - pub fn oaknode_colormanager_set_default_input_color_space(manager: CHandle, colorspace: *const c_char) -> c_int; - /// `oaknode_colormanager_get_reference_color_space` (two-stage string). - pub fn oaknode_colormanager_get_reference_color_space(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_get_compliant_color_space` (two-stage string). - pub fn oaknode_colormanager_get_compliant_color_space( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_is_dual(transition: CHandle, dual: *mut c_int) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_is_dual(transition, dual) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_get_connected_out_block(transition: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_get_connected_out_block(transition, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_transition_get_connected_in_block(transition: CHandle, out: *mut CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_transition_get_connected_in_block(transition, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_clip_add_cache_passthrough_from(clip: CHandle, other: CHandle) -> c_int { + unsafe { oaknode::ffi::block::oaknode_clip_add_cache_passthrough_from(clip, other) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_init(project: CHandle) -> CHandle { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_init(project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_free(manager: *mut CHandle) { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_free(manager) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_wrap_borrowed(native_manager: *mut c_void) -> CHandle { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_wrap_borrowed(native_manager) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_initialize(manager: CHandle) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_initialize(manager) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_set_up_default_config() -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_set_up_default_config() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_config_filename(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_config_filename(manager, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_set_config_filename(manager: CHandle, filename: *const c_char) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_set_config_filename(manager, filename) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_update_config_from_filename(manager: CHandle) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_update_config_from_filename(manager) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_default_input_color_space(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_default_input_color_space(manager, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_set_default_input_color_space(manager: CHandle, colorspace: *const c_char) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_set_default_input_color_space(manager, colorspace) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_reference_color_space(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_reference_color_space(manager, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_compliant_color_space( manager: CHandle, colorspace: *const c_char, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oaknode_colormanager_get_colorspace_for_ffmpeg_tags` (two-stage string). - pub fn oaknode_colormanager_get_colorspace_for_ffmpeg_tags( + ) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_compliant_color_space(manager, colorspace, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_colorspace_for_ffmpeg_tags( manager: CHandle, primaries: c_int, trc: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oaknode_colormanager_get_display_count`. - pub fn oaknode_colormanager_get_display_count(manager: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_colormanager_get_display_at` (two-stage string). - pub fn oaknode_colormanager_get_display_at(manager: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_get_default_display` (two-stage string). - pub fn oaknode_colormanager_get_default_display(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_get_view_count`. - pub fn oaknode_colormanager_get_view_count(manager: CHandle, display: *const c_char, count: *mut c_int) -> c_int; - /// `oaknode_colormanager_get_view_at` (two-stage string). - pub fn oaknode_colormanager_get_view_at( + ) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_colorspace_for_ffmpeg_tags(manager, primaries, trc, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_display_count(manager: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_display_count(manager, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_display_at(manager: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_display_at(manager, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_default_display(manager: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_default_display(manager, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_view_count(manager: CHandle, display: *const c_char, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_view_count(manager, display, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_view_at( manager: CHandle, display: *const c_char, index: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oaknode_colormanager_get_default_view` (two-stage string). - pub fn oaknode_colormanager_get_default_view(manager: CHandle, display: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_get_look_count`. - pub fn oaknode_colormanager_get_look_count(manager: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_colormanager_get_look_at` (two-stage string). - pub fn oaknode_colormanager_get_look_at(manager: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_get_colorspace_count`. - pub fn oaknode_colormanager_get_colorspace_count(manager: CHandle, count: *mut c_int) -> c_int; - /// `oaknode_colormanager_get_colorspace_at` (two-stage string). - pub fn oaknode_colormanager_get_colorspace_at(manager: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_colormanager_get_default_luma_coefs`. - pub fn oaknode_colormanager_get_default_luma_coefs(manager: CHandle, rgb: *mut f64) -> c_int; - /// `oaknode_colormanager_get_compliant_color_transform` — transform handle out. - pub fn oaknode_colormanager_get_compliant_color_transform( + ) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_view_at(manager, display, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_default_view(manager: CHandle, display: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_default_view(manager, display, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_look_count(manager: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_look_count(manager, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_look_at(manager: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_look_at(manager, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_colorspace_count(manager: CHandle, count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_colorspace_count(manager, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_colorspace_at(manager: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_colorspace_at(manager, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_default_luma_coefs(manager: CHandle, rgb: *mut f64) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_default_luma_coefs(manager, rgb) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_colormanager_get_compliant_color_transform( manager: CHandle, transform: CHandle, force_display: c_int, out: *mut CHandle, - ) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::colormanager::oaknode_colormanager_get_compliant_color_transform(manager, transform, force_display, out) } +} - // ---- include/node/traverser.h ------------------------------------------- - /// `oaknode_traverser_init` — new traverser, refcount 1. - pub fn oaknode_traverser_init() -> CHandle; - /// `oaknode_traverser_free` — NULL/empty no-op. - pub fn oaknode_traverser_free(traverser: *mut CHandle); - /// `oaknode_traverser_generate_database` — value database handle out. - pub fn oaknode_traverser_generate_database( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_init() -> CHandle { + unsafe { oaknode::ffi::traverser::oaknode_traverser_init() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_free(traverser: *mut CHandle) { + unsafe { oaknode::ffi::traverser::oaknode_traverser_free(traverser) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_generate_database( traverser: CHandle, node: CHandle, in_num: i64, @@ -885,53 +2186,107 @@ extern "C" { out_num: i64, out_den: i64, out_db: *mut CHandle, - ) -> c_int; - /// `oaknode_traverser_database_free` — NULL/empty no-op. - pub fn oaknode_traverser_database_free(db: *mut CHandle); - /// `oaknode_traverser_database_row_count`. - pub fn oaknode_traverser_database_row_count(db: CHandle, out_count: *mut c_int) -> c_int; - /// `oaknode_traverser_database_row_key_at` (two-stage string). - pub fn oaknode_traverser_database_row_key_at(db: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_traverser_database_row_value_count`. - pub fn oaknode_traverser_database_row_value_count(db: CHandle, key: *const c_char, out_count: *mut c_int) -> c_int; - /// `oaknode_traverser_database_value_at` — POD out. - pub fn oaknode_traverser_database_value_at( + ) -> c_int { + unsafe { oaknode::ffi::traverser::oaknode_traverser_generate_database(traverser, node, in_num, in_den, out_num, out_den, out_db) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_database_free(db: *mut CHandle) { + unsafe { oaknode::ffi::traverser::oaknode_traverser_database_free(db) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_database_row_count(db: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::traverser::oaknode_traverser_database_row_count(db, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_database_row_key_at(db: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::traverser::oaknode_traverser_database_row_key_at(db, index, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_database_row_value_count(db: CHandle, key: *const c_char, out_count: *mut c_int) -> c_int { + unsafe { oaknode::ffi::traverser::oaknode_traverser_database_row_value_count(db, key, out_count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_database_value_at( db: CHandle, key: *const c_char, index: c_int, out: *mut crate::node::OakNodeValue, - ) -> c_int; - /// `oaknode_traverser_database_value_string_at` (two-stage string). - pub fn oaknode_traverser_database_value_string_at( + ) -> c_int { + unsafe { oaknode::ffi::traverser::oaknode_traverser_database_value_at(db, key, index, out) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_traverser_database_value_string_at( db: CHandle, key: *const c_char, index: c_int, buf: *mut c_char, buf_size: c_int, - ) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::traverser::oaknode_traverser_database_value_string_at(db, key, index, buf, buf_size) } +} - // ---- include/node/serializer.h ------------------------------------------ - /// `oaknode_serializer_initialize`. - pub fn oaknode_serializer_initialize() -> c_int; - /// `oaknode_serializer_shutdown`. - pub fn oaknode_serializer_shutdown(); - /// `oaknode_serializer_savedata_create` — save-data handle, refcount 1. - pub fn oaknode_serializer_savedata_create(load_type: c_int, project: CHandle) -> CHandle; - /// `oaknode_serializer_savedata_free` — NULL/empty no-op. - pub fn oaknode_serializer_savedata_free(save_data: *mut CHandle); - /// `oaknode_serializer_savedata_set_nodes`. - pub fn oaknode_serializer_savedata_set_nodes(save_data: CHandle, nodes: *const CHandle, count: c_int) -> c_int; - /// `oaknode_serializer_savedata_set_property`. - pub fn oaknode_serializer_savedata_set_property( +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_initialize() -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_initialize() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_shutdown() { + unsafe { oaknode::ffi::serializer::oaknode_serializer_shutdown() } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_savedata_create(load_type: c_int, project: CHandle) -> CHandle { + unsafe { oaknode::ffi::serializer::oaknode_serializer_savedata_create(load_type, project) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_savedata_free(save_data: *mut CHandle) { + unsafe { oaknode::ffi::serializer::oaknode_serializer_savedata_free(save_data) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_savedata_set_nodes(save_data: CHandle, nodes: *const CHandle, count: c_int) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_savedata_set_nodes(save_data, nodes, count) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_savedata_set_property( save_data: CHandle, node: CHandle, key: *const c_char, value: *const c_char, - ) -> c_int; - /// `oaknode_serializer_save_to_xml` (two-stage string). - pub fn oaknode_serializer_save_to_xml(save_data: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaknode_serializer_load_from_xml` — load-data handle out. - pub fn oaknode_serializer_load_from_xml( + ) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_savedata_set_property(save_data, node, key, value) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_save_to_xml(save_data: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_save_to_xml(save_data, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_load_from_xml( project: CHandle, xml: *const c_char, load_type: c_int, @@ -939,25 +2294,49 @@ extern "C" { out_load_data: *mut CHandle, details_buf: *mut c_char, details_buf_size: c_int, - ) -> c_int; - /// `oaknode_serializer_loaddata_free` — NULL/empty no-op. - pub fn oaknode_serializer_loaddata_free(load_data: *mut CHandle); - /// `oaknode_serializer_loaddata_node_count`. - pub fn oaknode_serializer_loaddata_node_count(load_data: CHandle) -> c_int; - /// `oaknode_serializer_loaddata_node_at` — borrowed node handle. - pub fn oaknode_serializer_loaddata_node_at(load_data: CHandle, index: c_int) -> CHandle; - /// `oaknode_serializer_loaddata_get_property` (two-stage string). - pub fn oaknode_serializer_loaddata_get_property( + ) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_load_from_xml(project, xml, load_type, out_result, out_load_data, details_buf, details_buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_loaddata_free(load_data: *mut CHandle) { + unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_free(load_data) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_loaddata_node_count(load_data: CHandle) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_node_count(load_data) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_loaddata_node_at(load_data: CHandle, index: c_int) -> CHandle { + unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_node_at(load_data, index) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_loaddata_get_property( load_data: CHandle, node: CHandle, key: *const c_char, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oaknode_serializer_loaddata_connection_count`. - pub fn oaknode_serializer_loaddata_connection_count(load_data: CHandle) -> c_int; - /// `oaknode_serializer_loaddata_connection_at`. - pub fn oaknode_serializer_loaddata_connection_at( + ) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_get_property(load_data, node, key, buf, buf_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_loaddata_connection_count(load_data: CHandle) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_connection_count(load_data) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_loaddata_connection_at( load_data: CHandle, index: c_int, out_output_node: *mut CHandle, @@ -965,22 +2344,32 @@ extern "C" { input_id_buf: *mut c_char, input_id_buf_size: c_int, out_element: *mut c_int, - ) -> c_int; - /// `oaknode_serializer_save_to_file` — write a project file. - pub fn oaknode_serializer_save_to_file( + ) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_connection_at(load_data, index, out_output_node, out_input_node, input_id_buf, input_id_buf_size, out_element) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_save_to_file( project: CHandle, filename: *const c_char, use_compression: c_int, out_code: *mut c_int, details: *mut c_char, details_size: c_int, - ) -> c_int; - /// `oaknode_serializer_load_from_file` — read a project file. - pub fn oaknode_serializer_load_from_file( + ) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_save_to_file(project, filename, use_compression, out_code, details, details_size) } +} + +/// Direct call into the `oaknode` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaknode_serializer_load_from_file( project: CHandle, filename: *const c_char, out_code: *mut c_int, details: *mut c_char, details_size: c_int, - ) -> c_int; + ) -> c_int { + unsafe { oaknode::ffi::serializer::oaknode_serializer_load_from_file(project, filename, out_code, details, details_size) } } + diff --git a/src/engine/rust/src/bridge/plugin.rs b/src/engine/rust/src/bridge/plugin.rs index 2aaead214..976e45a8f 100644 --- a/src/engine/rust/src/bridge/plugin.rs +++ b/src/engine/rust/src/bridge/plugin.rs @@ -14,21 +14,65 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oakplugin C ABI bridge: direct Rust calls into the `oakplugin` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oakplugin`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oakplugin C ABI imports, mirroring the oakplugin crate's exports //! (`src/plugin/rust/src/ffi.rs`; headers `include/plugin/*.h`). use std::ffi::{c_char, c_int}; -extern "C" { - /// `oakplugin_host_scan` — scan bundle directories (NULL/0 uses the - /// default path set). - pub fn oakplugin_host_scan(bundle_dirs: *const *const c_char, dir_count: c_int) -> c_int; - /// `oakplugin_host_init` — initialize the OFX host (idempotent). - pub fn oakplugin_host_init() -> c_int; - /// `oakplugin_host_plugin_count` — number of discovered plugins. - pub fn oakplugin_host_plugin_count() -> c_int; - /// `oakplugin_host_plugin_id_at` — plugin id at index (two-stage). - pub fn oakplugin_host_plugin_id_at(index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oakplugin_host_plugin_label` — label for an id (two-stage). - pub fn oakplugin_host_plugin_label(plugin_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int; +/// Direct call into the `oakplugin` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakplugin_host_scan(bundle_dirs: *const *const c_char, dir_count: c_int) -> c_int { + unsafe { oakplugin::ffi::oakplugin_host_scan(bundle_dirs, dir_count) } } + +/// Direct call into the `oakplugin` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakplugin_host_init() -> c_int { + unsafe { oakplugin::ffi::oakplugin_host_init() } +} + +/// Direct call into the `oakplugin` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakplugin_host_plugin_count() -> c_int { + unsafe { oakplugin::ffi::oakplugin_host_plugin_count() } +} + +/// Direct call into the `oakplugin` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakplugin_host_plugin_id_at(index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oakplugin::ffi::oakplugin_host_plugin_id_at(index, buf, buf_size) } +} + +/// Direct call into the `oakplugin` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakplugin_host_plugin_label(plugin_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oakplugin::ffi::oakplugin_host_plugin_label(plugin_id, buf, buf_size) } +} + diff --git a/src/engine/rust/src/bridge/render.rs b/src/engine/rust/src/bridge/render.rs index 148a77cae..33e21d999 100644 --- a/src/engine/rust/src/bridge/render.rs +++ b/src/engine/rust/src/bridge/render.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oakrender C ABI bridge: direct Rust calls into the `oakrender` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oakrender`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oakrender C ABI imports, mirroring the oakrender crate's exports //! (`src/render/rust/src/ffi.rs`; headers `include/render/*.h`). @@ -21,110 +48,84 @@ use std::ffi::{c_char, c_double, c_int, c_void}; use crate::handle::CHandle; -/// `include/render/ticket.h` — video render ticket params mirror. All -/// handle fields are [`CHandle`] (borrowed unless noted). -#[repr(C)] -#[derive(Clone, Copy)] -pub struct OakVideoTicketParams { - /// Connected texture output node (borrowed). - pub output_node: CHandle, - /// By-value oakcommon video-params handle. - pub video_params: CHandle, - /// Borrowed oakcore audio-params handle, may be null. - pub audio_params: *const c_void, - /// Frame timestamp numerator. - pub time_num: i64, - /// Frame timestamp denominator. - pub time_den: i64, - /// Borrowed color manager, empty ctx = null. - pub color_manager: CHandle, - /// RenderMode::Mode as int. - pub mode: c_int, - /// 0/0 = off. - pub force_width: c_int, - /// 0/0 = off. - pub force_height: c_int, - /// Used when has_force_matrix != 0. - pub force_matrix: [c_double; 16], - /// 0/1. - pub has_force_matrix: c_int, - /// PixelFormat as int, -1 = off. - pub force_format: c_int, - /// 0 = off. - pub force_channel_count: c_int, - /// Borrowed; empty ctx = none. - pub force_color_output: CHandle, - /// By value; empty ctx = default. - pub force_color_transform: CHandle, - /// Borrowed frame cache; empty ctx = none. - pub cache: CHandle, -} +/// `include/render/ticket.h` — video render ticket params. Single-lib +/// unification: aliases the oakrender crate's POD (same `repr(C)` +/// layout; all handle fields are the shared [`CHandle`]). +pub type OakVideoTicketParams = oakrender::ffi::OakVideoTicketParams; + /// `include/render/renderer.h` — frame video-params POD returned by -/// `oakrender_codec_frame_get_params`. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct OakRenderVideoParams { - /// Width. - pub width: c_int, - /// Height. - pub height: c_int, - /// Frame duration numerator. - pub time_base_num: c_int, - /// Frame duration denominator. - pub time_base_den: c_int, - /// PixelFormat as int. - pub format: c_int, - /// Pixel aspect numerator. - pub pixel_aspect_num: c_int, - /// Pixel aspect denominator. - pub pixel_aspect_den: c_int, - /// Interlacing as int. - pub interlacing: c_int, - /// Color range as int. - pub color_range: c_int, - /// Preview divider. - pub divider: c_int, - /// Video type. - pub video_type: c_int, - /// Premultiplied alpha 0/1. - pub premultiplied_alpha: c_int, +/// `oakrender_codec_frame_get_params`. Single-lib unification: aliases +/// the oakrender crate's POD. +pub type OakRenderVideoParams = oakrender::ffi::OakRenderVideoParams; + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_display_renderer_create_dynamic(backend_id: *const c_char) -> CHandle { + unsafe { oakrender::ffi::renderer::oakrender_display_renderer_create_dynamic(backend_id) } } -extern "C" { - // ---- display renderer -------------------------------------------------- - /// `oakrender_display_renderer_create_dynamic` — named backend - /// ("opengl", "vulkan", "metal", "auto", ...). - pub fn oakrender_display_renderer_create_dynamic(backend_id: *const c_char) -> CHandle; - /// `oakrender_display_renderer_create_opengl` — direct OpenGL renderer. - pub fn oakrender_display_renderer_create_opengl() -> CHandle; - /// `oakrender_display_renderer_init` — NULL gl_context uses the - /// backend's default device/context path. - pub fn oakrender_display_renderer_init(renderer: CHandle, gl_context: *mut c_void) -> c_int; - /// `oakrender_display_renderer_destroy` — NULL/empty no-op. - pub fn oakrender_display_renderer_destroy(renderer: *mut CHandle); - /// `oakrender_display_renderer_is_open_gl` — 1/0. - pub fn oakrender_display_renderer_is_open_gl(renderer: CHandle) -> c_int; - /// `oakrender_display_renderer_is_vulkan` — 1/0. - pub fn oakrender_display_renderer_is_vulkan(renderer: CHandle) -> c_int; +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_display_renderer_create_opengl() -> CHandle { + unsafe { oakrender::ffi::renderer::oakrender_display_renderer_create_opengl() } +} - // ---- render manager ----------------------------------------------------- - /// `oakrender_manager_set_aggressive_gc`. - pub fn oakrender_manager_set_aggressive_gc(enabled: c_int) -> c_int; - /// `oakrender_set_cacher_multicam` — NULL clears. - pub fn oakrender_set_cacher_multicam(multicam_or_null: CHandle) -> c_int; - /// `oakrender_set_display_color_processor` — NULL clears. - pub fn oakrender_set_display_color_processor(p_or_null: CHandle) -> c_int; +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_display_renderer_init(renderer: CHandle, gl_context: *mut c_void) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_display_renderer_init(renderer, gl_context) } +} - // ---- render tickets ----------------------------------------------------- - /// `oakrender_ticket_render_frame`. - pub fn oakrender_ticket_render_frame( +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_display_renderer_destroy(renderer: *mut CHandle) { + unsafe { oakrender::ffi::renderer::oakrender_display_renderer_destroy(renderer) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_display_renderer_is_open_gl(renderer: CHandle) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_display_renderer_is_open_gl(renderer) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_display_renderer_is_vulkan(renderer: CHandle) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_display_renderer_is_vulkan(renderer) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_manager_set_aggressive_gc(enabled: c_int) -> c_int { + unsafe { oakrender::ffi::ticket::oakrender_manager_set_aggressive_gc(enabled) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_set_cacher_multicam(multicam_or_null: CHandle) -> c_int { + unsafe { oakrender::ffi::manager::oakrender_set_cacher_multicam(multicam_or_null) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_set_display_color_processor(p_or_null: CHandle) -> c_int { + unsafe { oakrender::ffi::manager::oakrender_set_display_color_processor(p_or_null) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_ticket_render_frame( params: *const OakVideoTicketParams, cb: Option, userdata: *mut c_void, - ) -> CHandle; - /// `oakrender_ticket_render_audio`. - pub fn oakrender_ticket_render_audio( + ) -> CHandle { + unsafe { oakrender::ffi::ticket::oakrender_ticket_render_frame(params, cb, userdata) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_ticket_render_audio( output_node: CHandle, in_num: i64, in_den: i64, @@ -134,61 +135,141 @@ extern "C" { mode: c_int, cb: Option, userdata: *mut c_void, - ) -> CHandle; - /// `oakrender_ticket_wait` — block until finished. - pub fn oakrender_ticket_wait(ticket: CHandle) -> c_int; - /// `oakrender_ticket_cancel`. - pub fn oakrender_ticket_cancel(ticket: CHandle) -> c_int; - /// `oakrender_ticket_get_frame` — `*out` receives an owned copy. - pub fn oakrender_ticket_get_frame(ticket: CHandle, out: *mut CHandle) -> c_int; - /// `oakrender_ticket_get_samples` — audio not implemented in the crate. - pub fn oakrender_ticket_get_samples(ticket: CHandle, out: *mut *mut c_void) -> c_int; - /// `oakrender_ticket_free` — NULL/empty no-op. - pub fn oakrender_ticket_free(ticket: *mut CHandle); + ) -> CHandle { + unsafe { + oakrender::ffi::ticket::oakrender_ticket_render_audio( + output_node, in_num, in_den, out_num, out_den, params as *const CHandle, mode, cb, + userdata, + ) + } +} - // ---- codec frame -------------------------------------------------------- - /// `oakrender_codec_frame_create` — refcount 1. - pub fn oakrender_codec_frame_create() -> CHandle; - /// `oakrender_codec_frame_retain` — addref, return copy. - pub fn oakrender_codec_frame_retain(frame: CHandle) -> CHandle; - /// `oakrender_codec_frame_free` — NULL/empty no-op. - pub fn oakrender_codec_frame_free(frame: *mut CHandle); - /// `oakrender_codec_frame_width`. - pub fn oakrender_codec_frame_width(frame: CHandle) -> c_int; - /// `oakrender_codec_frame_height`. - pub fn oakrender_codec_frame_height(frame: CHandle) -> c_int; - /// `oakrender_codec_frame_linesize_bytes`. - pub fn oakrender_codec_frame_linesize_bytes(frame: CHandle) -> c_int; - /// `oakrender_codec_frame_data` — borrowed. - pub fn oakrender_codec_frame_data(frame: CHandle) -> *mut c_void; - /// `oakrender_codec_frame_const_data` — borrowed. - pub fn oakrender_codec_frame_const_data(frame: CHandle) -> *const c_void; - /// `oakrender_codec_frame_is_allocated`. - pub fn oakrender_codec_frame_is_allocated(frame: CHandle) -> c_int; - /// `oakrender_codec_frame_get_params` — fills the params POD. - pub fn oakrender_codec_frame_get_params(frame: CHandle, out: *mut OakRenderVideoParams) -> c_int; +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_ticket_wait(ticket: CHandle) -> c_int { + unsafe { oakrender::ffi::ticket::oakrender_ticket_wait(ticket) } +} - // ---- color processor ---------------------------------------------------- - /// `oakrender_color_processor_create`. - pub fn oakrender_color_processor_create( +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_ticket_cancel(ticket: CHandle) -> c_int { + unsafe { oakrender::ffi::ticket::oakrender_ticket_cancel(ticket) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_ticket_get_frame(ticket: CHandle, out: *mut CHandle) -> c_int { + unsafe { oakrender::ffi::ticket::oakrender_ticket_get_frame(ticket, out) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_ticket_get_samples(ticket: CHandle, out: *mut *mut c_void) -> c_int { + unsafe { oakrender::ffi::ticket::oakrender_ticket_get_samples(ticket, out) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_ticket_free(ticket: *mut CHandle) { + unsafe { oakrender::ffi::ticket::oakrender_ticket_free(ticket) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_create() -> CHandle { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_create() } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_retain(frame: CHandle) -> CHandle { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_retain(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_free(frame: *mut CHandle) { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_free(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_width(frame: CHandle) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_width(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_height(frame: CHandle) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_height(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_linesize_bytes(frame: CHandle) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_linesize_bytes(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_data(frame: CHandle) -> *mut c_void { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_data(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_const_data(frame: CHandle) -> *const c_void { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_const_data(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_is_allocated(frame: CHandle) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_is_allocated(frame) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_codec_frame_get_params(frame: CHandle, out: *mut OakRenderVideoParams) -> c_int { + unsafe { oakrender::ffi::renderer::oakrender_codec_frame_get_params(frame, out) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_color_processor_create( src_space: *const c_char, dst_transform: *const c_char, direction: c_int, - ) -> CHandle; - /// `oakrender_color_processor_free` — NULL/empty no-op. - pub fn oakrender_color_processor_free(processor: *mut CHandle); - /// `oakrender_color_processor_is_valid`. - pub fn oakrender_color_processor_is_valid(processor: CHandle) -> c_int; - /// `oakrender_color_processor_create_transform` — manager + input + - /// oakcommon colortransform handle + direction. - pub fn oakrender_color_processor_create_transform( + ) -> CHandle { + unsafe { oakrender::ffi::color::oakrender_color_processor_create(src_space, dst_transform, direction) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_color_processor_free(processor: *mut CHandle) { + unsafe { oakrender::ffi::color::oakrender_color_processor_free(processor) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_color_processor_is_valid(processor: CHandle) -> c_int { + unsafe { oakrender::ffi::color::oakrender_color_processor_is_valid(processor) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_color_processor_create_transform( manager: CHandle, input: *const c_char, dest: CHandle, direction: c_int, - ) -> CHandle; - /// `oakrender_color_processor_convert` — single RGBA color. - pub fn oakrender_color_processor_convert( + ) -> CHandle { + unsafe { oakrender::ffi::color::oakrender_color_processor_create_transform(manager, input, dest, direction) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_color_processor_convert( processor: CHandle, ir: c_double, ig: c_double, @@ -198,19 +279,37 @@ extern "C" { out_g: *mut c_double, out_b: *mut c_double, out_a: *mut c_double, - ) -> c_int; - - // ---- color manager ------------------------------------------------------ - /// `oakrender_color_manager_set_up_default_config`. - pub fn oakrender_color_manager_set_up_default_config() -> c_int; - /// `oakrender_color_manager_get_config` (two-stage). - pub fn oakrender_color_manager_get_config(buf: *mut c_char, n: c_int) -> c_int; - - // ---- LUT extension enumeration ------------------------------------------ - /// `oakrender_lut_is_supported_extension`. - pub fn oakrender_lut_is_supported_extension(extension: *const c_char) -> c_int; - /// `oakrender_lut_supported_extensions_count`. - pub fn oakrender_lut_supported_extensions_count() -> c_int; - /// `oakrender_lut_supported_extension_at` (two-stage). - pub fn oakrender_lut_supported_extension_at(i: c_int, buf: *mut c_char, n: c_int) -> c_int; + ) -> c_int { + unsafe { oakrender::ffi::color::oakrender_color_processor_convert(processor, ir, ig, ib, ia, out_r, out_g, out_b, out_a) } } + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_color_manager_set_up_default_config() -> c_int { + unsafe { oakrender::ffi::color::oakrender_color_manager_set_up_default_config() } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_color_manager_get_config(buf: *mut c_char, n: c_int) -> c_int { + unsafe { oakrender::ffi::color::oakrender_color_manager_get_config(buf, n) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_lut_is_supported_extension(extension: *const c_char) -> c_int { + unsafe { oakrender::ffi::color::oakrender_lut_is_supported_extension(extension) } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_lut_supported_extensions_count() -> c_int { + unsafe { oakrender::ffi::color::oakrender_lut_supported_extensions_count() } +} + +/// Direct call into the `oakrender` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakrender_lut_supported_extension_at(i: c_int, buf: *mut c_char, n: c_int) -> c_int { + unsafe { oakrender::ffi::color::oakrender_lut_supported_extension_at(i, buf, n) } +} + diff --git a/src/engine/rust/src/bridge/task.rs b/src/engine/rust/src/bridge/task.rs index 9465e10a7..dfc22aac0 100644 --- a/src/engine/rust/src/bridge/task.rs +++ b/src/engine/rust/src/bridge/task.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oaktask C ABI bridge: direct Rust calls into the `oaktask` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oaktask`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oaktask C ABI imports, mirroring the oaktask crate's exports //! (`src/task/rust/src/ffi/{manager,task,project}.rs`; headers //! `include/task/*.h`). @@ -41,81 +68,217 @@ pub type OakTaskOtioImportConfirmFn = pub type OakTaskImageSequenceConfirmFn = unsafe extern "C" fn(filename: *const c_char, userdata: *mut c_void) -> c_int; +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_manager_init() -> c_int { + unsafe { oaktask::ffi::manager::oaktask_manager_init() } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_manager_shutdown() { + unsafe { oaktask::ffi::manager::oaktask_manager_shutdown() } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_register_codec_submitter() -> c_int { + unsafe { oaktask::ffi::manager::oaktask_register_codec_submitter() } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_manager_count() -> c_int { + unsafe { oaktask::ffi::manager::oaktask_manager_count() } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_manager_at(i: c_int) -> CHandle { + unsafe { oaktask::ffi::manager::oaktask_manager_at(i) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_manager_delete_finished() { + unsafe { oaktask::ffi::manager::oaktask_manager_delete_finished() } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_free(t: *mut CHandle) { + unsafe { oaktask::ffi::task::oaktask_task_free(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_start_sync(t: CHandle) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_start_sync(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_start(t: CHandle) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_start(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_cancel(t: CHandle) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_cancel(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_wait(t: CHandle) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_wait(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_is_finished(t: CHandle) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_is_finished(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_succeeded(t: CHandle) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_succeeded(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_title(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_title(t, buf, buf_size) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_error(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaktask::ffi::task::oaktask_task_error(t, buf, buf_size) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_task_subscribe(t: CHandle, cb: Option, userdata: *mut c_void) -> i64 { + unsafe { oaktask::ffi::task::oaktask_task_subscribe(t, cb, userdata) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_debug_alive_count() -> c_int { + unsafe { oaktask::ffi::task::oaktask_debug_alive_count() } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_create_project_load(filename: *const c_char) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_create_project_load(filename) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_load_take_project(t: CHandle) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_load_take_project(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_create_project_save(project: CHandle, filename_or_null: *const c_char, use_compression: c_int) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_create_project_save(project, filename_or_null, use_compression) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_create_project_import(folder: CHandle, project: CHandle, urls: *const *const c_char, url_count: c_int) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_create_project_import(folder, project, urls, url_count) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_import_take_command(t: CHandle) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_import_take_command(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_import_footage_count(t: CHandle) -> c_int { + unsafe { oaktask::ffi::project::oaktask_import_footage_count(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_import_footage_at(t: CHandle, index: c_int) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_import_footage_at(t, index) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_import_invalid_count(t: CHandle) -> c_int { + unsafe { oaktask::ffi::project::oaktask_import_invalid_count(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_import_invalid_at(t: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int { + unsafe { oaktask::ffi::project::oaktask_import_invalid_at(t, index, buf, buf_size) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_create_project_load_otio(filename: *const c_char) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_create_project_load_otio(filename) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_load_otio_take_project(t: CHandle) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_load_otio_take_project(t) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_create_project_save_otio(project: CHandle, filename: *const c_char) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_create_project_save_otio(project, filename) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_load_otio_set_confirm_cb(cb: Option, userdata: *mut c_void) { + unsafe { oaktask::ffi::project::oaktask_load_otio_set_confirm_cb(cb, userdata) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_create_precache(footage: CHandle, index: c_int, sequence: CHandle) -> CHandle { + unsafe { oaktask::ffi::project::oaktask_create_precache(footage, index, sequence) } +} + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +/// `oaktask_create_export` — crosses the encoding-params C ABI POD +/// (the facade keeps its own POD mirror). Kept as a link-time +/// `extern "C"` declaration against the frozen module C ABI. +pub fn oaktask_create_export( + viewer: CHandle, + color_manager: CHandle, + params: *const crate::bridge::codec::EncodingParamsPOD, + ) -> CHandle { + unsafe { oaktask_create_export_extern(viewer, color_manager, params) } +} + extern "C" { - // ---- include/task/manager.h --------------------------------------------- - /// `oaktask_manager_init` — start the global task manager. - pub fn oaktask_manager_init() -> c_int; - /// `oaktask_manager_shutdown`. - pub fn oaktask_manager_shutdown(); - /// `oaktask_register_codec_submitter`. - pub fn oaktask_register_codec_submitter() -> c_int; - /// `oaktask_manager_count` — running plus failed-but-kept tasks. - pub fn oaktask_manager_count() -> c_int; - /// `oaktask_manager_at` — borrowed task handle at index. - pub fn oaktask_manager_at(i: c_int) -> CHandle; - /// `oaktask_manager_delete_finished`. - pub fn oaktask_manager_delete_finished(); - - // ---- include/task/task.h ------------------------------------------------- - /// `oaktask_task_free` — release one reference; NULL/empty no-op. - pub fn oaktask_task_free(t: *mut CHandle); - /// `oaktask_task_start_sync` — run in the calling thread; 1 = succeeded. - pub fn oaktask_task_start_sync(t: CHandle) -> c_int; - /// `oaktask_task_start` — run on the task manager (transfers ownership). - pub fn oaktask_task_start(t: CHandle) -> c_int; - /// `oaktask_task_cancel`. - pub fn oaktask_task_cancel(t: CHandle) -> c_int; - /// `oaktask_task_wait` — wait for an asynchronously started task. - pub fn oaktask_task_wait(t: CHandle) -> c_int; - /// `oaktask_task_is_finished`. - pub fn oaktask_task_is_finished(t: CHandle) -> c_int; - /// `oaktask_task_succeeded`. - pub fn oaktask_task_succeeded(t: CHandle) -> c_int; - /// `oaktask_task_title` (two-stage string). - pub fn oaktask_task_title(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaktask_task_error` (two-stage string). - pub fn oaktask_task_error(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaktask_task_subscribe` — subscription id >= 0 or a negative code. - pub fn oaktask_task_subscribe(t: CHandle, cb: Option, userdata: *mut c_void) -> i64; - /// `oaktask_debug_alive_count`. - pub fn oaktask_debug_alive_count() -> c_int; - - // ---- include/task/project.h ---------------------------------------------- - /// `oaktask_create_project_load` — owned `ProjectLoadTask`. - pub fn oaktask_create_project_load(filename: *const c_char) -> CHandle; - /// `oaktask_load_take_project` — ownership transfer of the loaded project. - pub fn oaktask_load_take_project(t: CHandle) -> CHandle; - /// `oaktask_create_project_save` — owned `ProjectSaveTask`. - pub fn oaktask_create_project_save(project: CHandle, filename_or_null: *const c_char, use_compression: c_int) -> CHandle; - /// `oaktask_create_project_import` — owned `ProjectImportTask`. - pub fn oaktask_create_project_import(folder: CHandle, project: CHandle, urls: *const *const c_char, url_count: c_int) -> CHandle; - /// `oaktask_import_take_command` — ownership transfer of the undo command. - pub fn oaktask_import_take_command(t: CHandle) -> CHandle; - /// `oaktask_import_footage_count`. - pub fn oaktask_import_footage_count(t: CHandle) -> c_int; - /// `oaktask_import_footage_at` — addref'd footage handle. - pub fn oaktask_import_footage_at(t: CHandle, index: c_int) -> CHandle; - /// `oaktask_import_invalid_count`. - pub fn oaktask_import_invalid_count(t: CHandle) -> c_int; - /// `oaktask_import_invalid_at` (two-stage string). - pub fn oaktask_import_invalid_at(t: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int; - /// `oaktask_create_project_load_otio` — owned `LoadOTIOTask`. - pub fn oaktask_create_project_load_otio(filename: *const c_char) -> CHandle; - /// `oaktask_load_otio_take_project` — ownership transfer. - pub fn oaktask_load_otio_take_project(t: CHandle) -> CHandle; - /// `oaktask_create_project_save_otio` — owned `SaveOTIOTask`. - pub fn oaktask_create_project_save_otio(project: CHandle, filename: *const c_char) -> CHandle; - /// `oaktask_load_otio_set_confirm_cb` — install/clear the confirm callback. - pub fn oaktask_load_otio_set_confirm_cb(cb: Option, userdata: *mut c_void); - /// `oaktask_create_precache` — owned `PreCacheTask`. - pub fn oaktask_create_precache(footage: CHandle, index: c_int, sequence: CHandle) -> CHandle; - /// `oaktask_create_export` — owned `ExportTask`; `params` is the - /// encoding-params POD (facade's `EncodingParamsPOD`). - pub fn oaktask_create_export( + #[link_name = "oaktask_create_export"] + pub fn oaktask_create_export_extern( viewer: CHandle, color_manager: CHandle, params: *const crate::bridge::codec::EncodingParamsPOD, ) -> CHandle; - /// `oaktask_import_set_image_sequence_confirm_cb` — install/clear. - pub fn oaktask_import_set_image_sequence_confirm_cb(cb: Option, userdata: *mut c_void); } + +/// Direct call into the `oaktask` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktask_import_set_image_sequence_confirm_cb(cb: Option, userdata: *mut c_void) { + unsafe { oaktask::ffi::project::oaktask_import_set_image_sequence_confirm_cb(cb, userdata) } +} + diff --git a/src/engine/rust/src/bridge/timeline.rs b/src/engine/rust/src/bridge/timeline.rs index 41589c93f..09e4c328c 100644 --- a/src/engine/rust/src/bridge/timeline.rs +++ b/src/engine/rust/src/bridge/timeline.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oaktimeline C ABI bridge: direct Rust calls into the `oaktimeline` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oaktimeline`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oaktimeline C ABI imports, mirroring the oaktimeline crate's exports //! (`src/timeline/rust/src/ffi.rs`; headers `include/timeline/*.h`). //! @@ -30,15 +57,28 @@ use crate::handle::CHandle; // oaktimeline_marker_list_create / free / of / add / count / at / // add_command / remove_at_command / set_time_command / // set_props_command / list_load / list_save. -extern "C" { - /// `oaktimeline_marker_list_create` — new owning list, refcount 1. - pub fn oaktimeline_marker_list_create() -> CHandle; - /// `oaktimeline_marker_list_of` — borrowed list of a viewer node. - pub fn oaktimeline_marker_list_of(owner: CHandle) -> CHandle; - /// `oaktimeline_marker_list_free` — NULL/empty no-op; clears `list->ctx`. - pub fn oaktimeline_marker_list_free(list: *mut CHandle); - /// `oaktimeline_marker_add` — append a marker directly (no command). - pub fn oaktimeline_marker_add( + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_list_create() -> CHandle { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_create() } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_list_of(owner: CHandle) -> CHandle { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_of(owner) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_list_free(list: *mut CHandle) { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_free(list) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_add( list: CHandle, in_num: c_int, in_den: c_int, @@ -46,11 +86,19 @@ extern "C" { out_den: c_int, name: *const c_char, color: c_int, - ) -> c_int; - /// `oaktimeline_marker_count` — number of markers. - pub fn oaktimeline_marker_count(list: CHandle, out_count: *mut c_int) -> c_int; - /// `oaktimeline_marker_at` — marker at index; name two-stage. - pub fn oaktimeline_marker_at( + ) -> c_int { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_add(list, in_num, in_den, out_num, out_den, name, color) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_count(list: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_count(list, out_count) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_at( list: CHandle, index: c_int, in_num: *mut c_int, @@ -60,68 +108,118 @@ extern "C" { color: *mut c_int, name_buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oaktimeline_marker_add_command` — owned `MarkerAddCommand`. - pub fn oaktimeline_marker_add_command( - list: CHandle, - in_num: c_int, - in_den: c_int, - out_num: c_int, - out_den: c_int, - name: *const c_char, - color: c_int, - ) -> CHandle; - /// `oaktimeline_marker_remove_at_command` — owned `MarkerRemoveCommand`. - pub fn oaktimeline_marker_remove_at_command(list: CHandle, index: c_int) -> CHandle; - /// `oaktimeline_marker_set_time_command` — owned `MarkerChangeTimeCommand`. - pub fn oaktimeline_marker_set_time_command( - list: CHandle, - index: c_int, - in_num: c_int, - in_den: c_int, - out_num: c_int, - out_den: c_int, - ) -> CHandle; - /// `oaktimeline_marker_set_props_command` — owned color/name command. - pub fn oaktimeline_marker_set_props_command( - list: CHandle, - index: c_int, - color: c_int, - name: *const c_char, - ) -> CHandle; - /// `oaktimeline_marker_list_load` — read from an oakcommon reader. - pub fn oaktimeline_marker_list_load(list: CHandle, reader: CHandle) -> c_int; - /// `oaktimeline_marker_list_save` — write to an oakcommon writer. - pub fn oaktimeline_marker_list_save(list: CHandle, writer: CHandle) -> c_int; + ) -> c_int { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_at(list, index, in_num, in_den, out_num, out_den, color, name_buf, buf_size) } +} - // ---- include/timeline/workarea.h ---------------------------------------- - /// `oaktimeline_workarea_create` — new owning work area, refcount 1. - pub fn oaktimeline_workarea_create() -> CHandle; - /// `oaktimeline_workarea_of` — borrowed work area of a viewer node. - pub fn oaktimeline_workarea_of(owner: CHandle) -> CHandle; - /// `oaktimeline_workarea_free` — NULL/empty no-op; clears `w->ctx`. - pub fn oaktimeline_workarea_free(w: *mut CHandle); - /// `oaktimeline_workarea_set_enabled` — live. - pub fn oaktimeline_workarea_set_enabled(w: CHandle, enabled: c_int) -> c_int; - /// `oaktimeline_workarea_get` — state out; params may be NULL. - pub fn oaktimeline_workarea_get( +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_add_command( + list: CHandle, + in_num: c_int, + in_den: c_int, + out_num: c_int, + out_den: c_int, + name: *const c_char, + color: c_int, + ) -> CHandle { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_add_command(list, in_num, in_den, out_num, out_den, name, color) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_remove_at_command(list: CHandle, index: c_int) -> CHandle { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_remove_at_command(list, index) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_set_time_command( + list: CHandle, + index: c_int, + in_num: c_int, + in_den: c_int, + out_num: c_int, + out_den: c_int, + ) -> CHandle { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_set_time_command(list, index, in_num, in_den, out_num, out_den) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_set_props_command( + list: CHandle, + index: c_int, + color: c_int, + name: *const c_char, + ) -> CHandle { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_set_props_command(list, index, color, name) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_list_load(list: CHandle, reader: CHandle) -> c_int { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_load(list, reader) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_marker_list_save(list: CHandle, writer: CHandle) -> c_int { + unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_save(list, writer) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_create() -> CHandle { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_create() } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_of(owner: CHandle) -> CHandle { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_of(owner) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_free(w: *mut CHandle) { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_free(w) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_set_enabled(w: CHandle, enabled: c_int) -> c_int { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_enabled(w, enabled) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_get( w: CHandle, in_num: *mut c_int, in_den: *mut c_int, out_num: *mut c_int, out_den: *mut c_int, enabled: *mut c_int, - ) -> c_int; - /// `oaktimeline_workarea_set_range` — live. - pub fn oaktimeline_workarea_set_range( + ) -> c_int { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_get(w, in_num, in_den, out_num, out_den, enabled) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_set_range( w: CHandle, in_num: c_int, in_den: c_int, out_num: c_int, out_den: c_int, - ) -> c_int; - /// `oaktimeline_workarea_set_range_command` — owned command, old range from caller. - pub fn oaktimeline_workarea_set_range_command( + ) -> c_int { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_range(w, in_num, in_den, out_num, out_den) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_set_range_command( w: CHandle, in_num: c_int, in_den: c_int, @@ -131,57 +229,102 @@ extern "C" { old_in_den: c_int, old_out_num: c_int, old_out_den: c_int, - ) -> CHandle; - /// `oaktimeline_workarea_set_enabled_command` — owned command. - pub fn oaktimeline_workarea_set_enabled_command(w: CHandle, enabled: c_int) -> CHandle; - /// `oaktimeline_workarea_reset` — the reset sentinel range. - pub fn oaktimeline_workarea_reset( + ) -> CHandle { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_range_command(w, in_num, in_den, out_num, out_den, old_in_num, old_in_den, old_out_num, old_out_den) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_set_enabled_command(w: CHandle, enabled: c_int) -> CHandle { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_enabled_command(w, enabled) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_reset( in_num: *mut c_int, in_den: *mut c_int, out_num: *mut c_int, out_den: *mut c_int, - ) -> c_int; - /// `oaktimeline_workarea_load` — read from an oakcommon reader. - pub fn oaktimeline_workarea_load(w: CHandle, reader: CHandle) -> c_int; - /// `oaktimeline_workarea_save` — write to an oakcommon writer. - pub fn oaktimeline_workarea_save(w: CHandle, writer: CHandle) -> c_int; + ) -> c_int { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_reset(in_num, in_den, out_num, out_den) } +} - // ---- include/timeline/edit.h -------------------------------------------- - /// `oaktimeline_add_track_command` — owned `TimelineAddTrackCommand`. - pub fn oaktimeline_add_track_command(list: CHandle) -> CHandle; - /// `oaktimeline_remove_track_command` — owned `TimelineRemoveTrackCommand`. - pub fn oaktimeline_remove_track_command(track: CHandle) -> CHandle; - /// `oaktimeline_place_block_command` — owned `TrackPlaceBlockCommand`. - pub fn oaktimeline_place_block_command( +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_load(w: CHandle, reader: CHandle) -> c_int { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_load(w, reader) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_workarea_save(w: CHandle, writer: CHandle) -> c_int { + unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_save(w, writer) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_add_track_command(list: CHandle) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_add_track_command(list) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_remove_track_command(track: CHandle) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_remove_track_command(track) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_place_block_command( list: CHandle, track_index: c_int, block: CHandle, in_num: i64, in_den: i64, - ) -> CHandle; - /// `oaktimeline_replace_block_with_gap_command` — owned command. - pub fn oaktimeline_replace_block_with_gap_command(track: CHandle, block: CHandle) -> CHandle; - /// `oaktimeline_trim_command` — owned `BlockTrimCommand`; `mode` is an - /// `OakTimelineMovementMode` value. - pub fn oaktimeline_trim_command( + ) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_place_block_command(list, track_index, block, in_num, in_den) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_replace_block_with_gap_command(track: CHandle, block: CHandle) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_replace_block_with_gap_command(track, block) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_trim_command( track: CHandle, block: CHandle, new_length_num: i64, new_length_den: i64, mode: c_int, - ) -> CHandle; - /// `oaktimeline_split_command` — owned `BlockSplitCommand` (one point). - pub fn oaktimeline_split_command(blocks: *const CHandle, count: c_int, point_num: i64, point_den: i64) -> CHandle; - /// `oaktimeline_split_preserving_links_command` — owned command. - pub fn oaktimeline_split_preserving_links_command( + ) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_trim_command(track, block, new_length_num, new_length_den, mode) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_split_command(blocks: *const CHandle, count: c_int, point_num: i64, point_den: i64) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_split_command(blocks, count, point_num, point_den) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_split_preserving_links_command( blocks: *const CHandle, count: c_int, point_nums: *const i64, point_dens: *const i64, time_count: c_int, - ) -> CHandle; - /// `oaktimeline_ripple_delete_gaps_command` — owned command. - pub fn oaktimeline_ripple_delete_gaps_command( + ) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_split_preserving_links_command(blocks, count, point_nums, point_dens, time_count) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_ripple_delete_gaps_command( sequence: CHandle, in_nums: *const i64, in_dens: *const i64, @@ -189,9 +332,13 @@ extern "C" { out_dens: *const i64, tracks: *const CHandle, range_count: c_int, - ) -> CHandle; - /// `oaktimeline_slide_command` — owned `TrackSlideCommand`. - pub fn oaktimeline_slide_command( + ) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_ripple_delete_gaps_command(sequence, in_nums, in_dens, out_nums, out_dens, tracks, range_count) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_slide_command( track: CHandle, blocks: *const CHandle, block_count: c_int, @@ -199,22 +346,31 @@ extern "C" { out_adjacent: CHandle, movement_num: i64, movement_den: i64, - ) -> CHandle; - /// `oaktimeline_ripple_remove_area_command` — owned - /// `TrackRippleRemoveAreaCommand`. - pub fn oaktimeline_ripple_remove_area_command( + ) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_slide_command(track, blocks, block_count, in_adjacent, out_adjacent, movement_num, movement_den) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_ripple_remove_area_command( track: CHandle, in_num: i64, in_den: i64, out_num: i64, out_den: i64, - ) -> CHandle; - /// `oaktimeline_insert_gaps_command` — owned `TrackListInsertGaps`. - pub fn oaktimeline_insert_gaps_command( + ) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_ripple_remove_area_command(track, in_num, in_den, out_num, out_den) } +} + +/// Direct call into the `oaktimeline` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oaktimeline_insert_gaps_command( list: CHandle, point_num: i64, point_den: i64, length_num: i64, length_den: i64, - ) -> CHandle; + ) -> CHandle { + unsafe { oaktimeline::ffi::edit::oaktimeline_insert_gaps_command(list, point_num, point_den, length_num, length_den) } } + diff --git a/src/engine/rust/src/bridge/undo.rs b/src/engine/rust/src/bridge/undo.rs index 10efd712a..1dc626017 100644 --- a/src/engine/rust/src/bridge/undo.rs +++ b/src/engine/rust/src/bridge/undo.rs @@ -14,6 +14,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! oakundo C ABI bridge: direct Rust calls into the `oakundo` crate. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every +//! call below is a compile-time Rust call into `oakundo`'s `ffi` (the +//! `#[no_mangle]` exports stay in the dylib for the external C ABI; +//! internal callers bypass them). Handles cross as the shared +//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"` +//! declaration (resolved at link time against the sibling crate in the +//! same dylib) are the host `oakcore_*` symbols and the encoding-params +//! C ABI POD crossings (the facade keeps its own POD mirrors there). + +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + //! oakundo C ABI imports, mirroring the oakundo crate's exports //! (`src/undo/rust/src/ffi.rs`; headers `include/undo/*.h`). @@ -21,82 +48,161 @@ use std::ffi::{c_char, c_int}; use crate::handle::CHandle; -extern "C" { - /// `oakundo_command_init` — vtable-backed command, refcount 1. - pub fn oakundo_command_init( + +/// `include/undo/undocommand.h` — callback table backing a +/// caller-defined undo command. Single-lib unification: aliases the +/// oakundo crate's vtable POD. +pub type OakUndoCommandVtable = oakundo::undocommand::OakUndoCommandVtable; + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_init( vtable: *const OakUndoCommandVtable, userdata: *mut std::ffi::c_void, - ) -> CHandle; - /// `oakundo_command_init_multi` — empty multi command, refcount 1. - pub fn oakundo_command_init_multi() -> CHandle; - /// `oakundo_command_multi_add_child` (stack takes one child ref). - pub fn oakundo_command_multi_add_child(multi: CHandle, child: CHandle) -> c_int; - /// `oakundo_command_multi_child_count`. - pub fn oakundo_command_multi_child_count(multi: CHandle, out_count: *mut c_int) -> c_int; - /// `oakundo_command_multi_child` (returned handle carries own ref). - pub fn oakundo_command_multi_child( + ) -> CHandle { + unsafe { oakundo::ffi::command::oakundo_command_init(vtable, userdata) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_init_multi() -> CHandle { + unsafe { oakundo::ffi::command::oakundo_command_init_multi() } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_multi_add_child(multi: CHandle, child: CHandle) -> c_int { + unsafe { oakundo::ffi::command::oakundo_command_multi_add_child(multi, child) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_multi_child_count(multi: CHandle, out_count: *mut c_int) -> c_int { + unsafe { oakundo::ffi::command::oakundo_command_multi_child_count(multi, out_count) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_multi_child( multi: CHandle, index: c_int, out_child: *mut CHandle, - ) -> c_int; - /// `oakundo_command_redo_now`. - pub fn oakundo_command_redo_now(command: CHandle) -> c_int; - /// `oakundo_command_undo_now`. - pub fn oakundo_command_undo_now(command: CHandle) -> c_int; - /// `oakundo_command_free` — NULL/empty no-op; clears `command->ctx`. - pub fn oakundo_command_free(command: *mut CHandle); - /// `oakundo_undostack_init` — fresh stack, refcount 1. - pub fn oakundo_undostack_init() -> CHandle; - /// `oakundo_undostack_free` — NULL/empty no-op; clears `stack->ctx`. - pub fn oakundo_undostack_free(stack: *mut CHandle); - /// `oakundo_undostack_push` — redo then record; drops redoable tail. - pub fn oakundo_undostack_push(stack: CHandle, command: CHandle, name: *const c_char) -> c_int; - /// `oakundo_undostack_push_pre_executed` — record without redoing. - pub fn oakundo_undostack_push_pre_executed( + ) -> c_int { + unsafe { oakundo::ffi::command::oakundo_command_multi_child(multi, index, out_child) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_redo_now(command: CHandle) -> c_int { + unsafe { oakundo::ffi::command::oakundo_command_redo_now(command) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_undo_now(command: CHandle) -> c_int { + unsafe { oakundo::ffi::command::oakundo_command_undo_now(command) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_command_free(command: *mut CHandle) { + unsafe { oakundo::ffi::command::oakundo_command_free(command) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_init() -> CHandle { + unsafe { oakundo::ffi::undostack::oakundo_undostack_init() } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_free(stack: *mut CHandle) { + unsafe { oakundo::ffi::undostack::oakundo_undostack_free(stack) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_push(stack: CHandle, command: CHandle, name: *const c_char) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_push(stack, command, name) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_push_pre_executed( stack: CHandle, command: CHandle, name: *const c_char, - ) -> c_int; - /// `oakundo_undostack_undo`. - pub fn oakundo_undostack_undo(stack: CHandle) -> c_int; - /// `oakundo_undostack_redo`. - pub fn oakundo_undostack_redo(stack: CHandle) -> c_int; - /// `oakundo_undostack_jump` (clamped to 0; `index` is i64). - pub fn oakundo_undostack_jump(stack: CHandle, index: i64) -> c_int; - /// `oakundo_undostack_clear`. - pub fn oakundo_undostack_clear(stack: CHandle) -> c_int; - /// `oakundo_undostack_can_undo`. - pub fn oakundo_undostack_can_undo(stack: CHandle, out_value: *mut c_int) -> c_int; - /// `oakundo_undostack_can_redo`. - pub fn oakundo_undostack_can_redo(stack: CHandle, out_value: *mut c_int) -> c_int; - /// `oakundo_undostack_count`. - pub fn oakundo_undostack_count(stack: CHandle, out_count: *mut i64) -> c_int; - /// `oakundo_undostack_index`. - pub fn oakundo_undostack_index(stack: CHandle, out_index: *mut i64) -> c_int; - /// `oakundo_undostack_command_text` (two-stage string getter). - pub fn oakundo_undostack_command_text( + ) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_push_pre_executed(stack, command, name) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_undo(stack: CHandle) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_undo(stack) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_redo(stack: CHandle) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_redo(stack) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_jump(stack: CHandle, index: i64) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_jump(stack, index) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_clear(stack: CHandle) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_clear(stack) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_can_undo(stack: CHandle, out_value: *mut c_int) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_can_undo(stack, out_value) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_can_redo(stack: CHandle, out_value: *mut c_int) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_can_redo(stack, out_value) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_count(stack: CHandle, out_count: *mut i64) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_count(stack, out_count) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_index(stack: CHandle, out_index: *mut i64) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_index(stack, out_index) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_command_text( stack: CHandle, row: i64, buf: *mut c_char, buf_size: c_int, - ) -> c_int; - /// `oakundo_undostack_command_is_done`. - pub fn oakundo_undostack_command_is_done( + ) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_command_text(stack, row, buf, buf_size) } +} + +/// Direct call into the `oakundo` crate (single-lib unification; the +/// `#[no_mangle]` export stays for the external C ABI). +pub fn oakundo_undostack_command_is_done( stack: CHandle, row: i64, out_value: *mut c_int, - ) -> c_int; + ) -> c_int { + unsafe { oakundo::ffi::undostack::oakundo_undostack_command_is_done(stack, row, out_value) } } -/// `include/undo/undocommand.h` — callback table backing a -/// caller-defined undo command. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct OakUndoCommandVtable { - /// Redo callback (NULL = no-op). - pub redo: Option, - /// Undo callback (NULL = no-op). - pub undo: Option, - /// Destruction callback releasing `userdata`. - pub free_fn: Option, -} diff --git a/src/engine/rust/src/handle.rs b/src/engine/rust/src/handle.rs index 9ed001a7b..67186b1d9 100644 --- a/src/engine/rust/src/handle.rs +++ b/src/engine/rust/src/handle.rs @@ -40,63 +40,13 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::error::{Error, Result}; -/// ABI-neutral mirror of the module handle struct -/// (`{ctx, addref, release, abi_version}`). Structurally identical to -/// every `Oak` value handle in `include//*.h`, so the -/// facade can copy a handle across the module boundary without knowing -/// the module's concrete type names. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -impl CHandle { - /// The empty handle. - pub const fn null() -> Self { - CHandle { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: 0, - } - } - - /// Whether this is the empty (zero) handle. - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } - - /// Take an additional reference through the handle's `addref` and - /// return the (now refcount-incremented) copy. - /// - /// # Safety - /// `self` must be a live handle returned by a module function. - pub unsafe fn addref(&self) -> Self { - let mut copy = *self; - if let Some(addref) = copy.addref { - let _ = &mut copy; - unsafe { - addref(copy.ctx); - } - } - copy - } -} - -// Module handles follow the shared_ptr-like convention of -// `include/common/handle.h`: they are opaque, refcounted and safe to -// share across threads (the module crates themselves use them behind -// mutexes). The facade therefore declares them Send + Sync. -unsafe impl Send for CHandle {} -unsafe impl Sync for CHandle {} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// by every module crate, so the facade can pass a handle straight into a +/// module's `pub` Rust functions without an `extern "C"` declaration. +/// `Clone + Copy + Send + Sync` come from the shared type. +pub use oakcore_rs::handle::CHandle; /// Engine opaque handle types, one per `typedef struct OakEngine*` in /// `engine/include/oakengine/*.h`. All are thin newtype wrappers around a diff --git a/src/engine/rust/src/node.rs b/src/engine/rust/src/node.rs index f0f3e8665..512b84941 100644 --- a/src/engine/rust/src/node.rs +++ b/src/engine/rust/src/node.rs @@ -33,20 +33,11 @@ use crate::undo::push_or_run; /// `engine/include/oakengine/node.h` — POD mirror of `oak_node_value`. /// -/// Layout-identical to the module's `oaknode_value`, so the facade hands -/// the engine POD straight to the oaknode bridge. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct OakNodeValue { - /// `oak_node_value_type`. - pub type_: c_int, - /// INT/COMBO value, BOOL 0/1, RATIONAL numerator. - pub num: i64, - /// RATIONAL denominator. - pub den: i64, - /// FLOAT f[0]; VEC2/3/4 f[0..n-1]; COLOR r,g,b,a. - pub f: [f64; 4], -} +/// Single-lib unification: aliases the oaknode crate's POD (the module +/// C ABI struct `oak_node_value`), so the facade can pass it straight +/// into `oaknode::ffi` functions without an `extern "C"` declaration. +/// The field is named `kind` on the shared type (was `type_`). +pub type OakNodeValue = oaknode::value::OakNodeValue; /// `engine/include/oakengine/footage.h` — POD mirror of /// `oak_footage_video_info` (olive::VideoParams stream description). @@ -5584,7 +5575,7 @@ pub unsafe extern "C" fn oakengine_node_value_split_to_tracks( let count = oakengine_node_value_keyframe_track_count(c_type).min(track_count); for i in 0..count as usize { let mut t = OakNodeValue { - type_: c_type, + kind: c_type, num: 0, den: 0, f: [0.0; 4], @@ -5604,7 +5595,7 @@ pub unsafe extern "C" fn oakengine_node_value_split_to_tracks( t.f[0] = n.f[0]; } _ => { - t.type_ = c_type; + t.kind = c_type; t.f = n.f; } } @@ -5627,7 +5618,7 @@ pub unsafe extern "C" fn oakengine_node_value_combine_tracks( return Err(Error::Invalid); } let mut out = OakNodeValue { - type_: c_type, + kind: c_type, num: 0, den: 0, f: [0.0; 4], diff --git a/src/engine/rust/src/timeline.rs b/src/engine/rust/src/timeline.rs index a9be7a21d..3f44438c0 100644 --- a/src/engine/rust/src/timeline.rs +++ b/src/engine/rust/src/timeline.rs @@ -4794,7 +4794,7 @@ pub unsafe extern "C" fn oakengine_track_block_at_time( unsafe fn track_nearest_boxed( track: *const OakEngineTrack, timestamp: i64, - via: unsafe extern "C" fn(CHandle, c_int, c_int, *mut CHandle) -> c_int, + via: fn(CHandle, c_int, c_int, *mut CHandle) -> c_int, ) -> *mut OakEngineBlock { guard_ptr(|| unsafe { if track.is_null() { diff --git a/src/engine/rust/tests/node.rs b/src/engine/rust/tests/node.rs index 50972686c..dbee6012a 100644 --- a/src/engine/rust/tests/node.rs +++ b/src/engine/rust/tests/node.rs @@ -75,7 +75,7 @@ fn force_oakundo_command_link() -> usize { /// A float POD value. fn float_value(x: f64) -> OakNodeValue { OakNodeValue { - type_: 2, // OAK_NODE_VALUE_FLOAT + kind: 2, // OAK_NODE_VALUE_FLOAT num: 0, den: 0, f: [x, 0.0, 0.0, 0.0], @@ -229,7 +229,7 @@ fn project_node_keyframe_lifecycle() { unsafe { oakengine_node_get_input(value, c"value_in".as_ptr(), &mut out) }, 0 ); - assert_eq!(out.type_, 2); + assert_eq!(out.kind, 2); assert!((out.f[0] - 3.5).abs() < 1e-6); // ---- connect / disconnect ------------------------------------------- @@ -265,7 +265,7 @@ fn project_node_keyframe_lifecycle() { unsafe { oakengine_node_get_input_at_time(value, c"value_in".as_ptr(), -1, -1, 0, 0, &mut at) }, 0 ); - assert_eq!(at.type_, 2); + assert_eq!(at.kind, 2); assert!((at.f[0] - 0.5).abs() < 1e-6); // ---- project save → fresh load round-trip --------------------------- diff --git a/src/node/rust/Cargo.lock b/src/node/rust/Cargo.lock index a9da9ff03..e7910754e 100644 --- a/src/node/rust/Cargo.lock +++ b/src/node/rust/Cargo.lock @@ -2,6 +2,168 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "find-msvc-tools" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "tiff", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "oakcommon" +version = "0.1.0" +dependencies = [ + "image", + "log", + "oakcore-rs", + "ocio-rs", + "quick-xml", +] + [[package]] name = "oakcore-rs" version = "0.1.0" @@ -9,6 +171,178 @@ version = "0.1.0" [[package]] name = "oaknode" version = "0.1.0" +dependencies = [ + "oakcommon", + "oakcore-rs", + "oakundo", +] + +[[package]] +name = "oakundo" +version = "0.1.0" dependencies = [ "oakcore-rs", ] + +[[package]] +name = "ocio-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3492534019b59e29dba06014f907dd12824537ed4d293d4108c4bfc669de7fd" +dependencies = [ + "ocio-sys", + "thiserror", +] + +[[package]] +name = "ocio-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63251d72d848de5eda39d59cd6490260cf031738ebd518ea37d76b5aae614ec" +dependencies = [ + "cc", + "cmake", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zune-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/src/node/rust/Cargo.toml b/src/node/rust/Cargo.toml index c5d26e90c..0b812f4ac 100644 --- a/src/node/rust/Cargo.toml +++ b/src/node/rust/Cargo.toml @@ -14,6 +14,8 @@ panic = "unwind" [dependencies] oakcore-rs = { path = "../../oakcore-rs" } +oakcommon = { path = "../../common/rust" } +oakundo = { path = "../../undo/rust" } [features] # In-crate stubs for the oakundo C ABI (and other module bridges) so diff --git a/src/node/rust/src/bridge/undo.rs b/src/node/rust/src/bridge/undo.rs index cb6338b9b..4c1500beb 100644 --- a/src/node/rust/src/bridge/undo.rs +++ b/src/node/rust/src/bridge/undo.rs @@ -14,19 +14,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! oakundo C ABI imports. Undo commands are created through the C ABI -//! vtable (`oakundo_command_init` with Rust closures as userdata) — no -//! C++ UndoCommand subclassing exists on this side. Symbols resolve via -//! `dlsym(RTLD_DEFAULT)` (see [`super`]). +//! oakundo C ABI calls — now direct Rust calls into the oakundo crate +//! (single-lib unification, see `docs/zh/plans/riir/single-lib.md`). +//! Undo commands are created through the C ABI vtable +//! (`oakundo_command_init` with Rust closures as userdata) — no C++ +//! UndoCommand subclassing exists on this side. //! //! ## Test stubs (`--features test-stubs`) //! -//! `cargo test` builds without liboakundo, so the feature compiles -//! in-crate `#[no_mangle]` implementations of the undo C ABI -//! (see [`stub`]) that run Rust closures directly. `dlsym` then resolves -//! the stub symbols from the test binary's global scope, so the undoable -//! exports run end-to-end in tests. Real module builds (feature off) -//! resolve the actual oakundo library. +//! With the direct dependency, the real oakundo rlib is linked into +//! every build and test; the `test-stubs` feature still compiles +//! in-crate `#[no_mangle]` implementations of the undo C ABI (see +//! [`stub`]) for environments that link without oakundo. Do not enable +//! the feature in a binary that also links oakundo (duplicate symbols). use std::ffi::c_int; use std::sync::atomic::{AtomicBool, Ordering}; @@ -34,17 +34,9 @@ use std::sync::atomic::{AtomicBool, Ordering}; use crate::handle::CHandle; /// `OakUndoCommandVtable` (include/undo/undocommand.h) — the callback -/// table backing a caller-defined undo command. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct Vtable { - /// Execute the redo. - pub redo: Option, - /// Execute the undo. - pub undo: Option, - /// Release `userdata` (invoked when the command is destroyed). - pub free_fn: Option, -} +/// table backing a caller-defined undo command. Single-lib unification: +/// aliases the oakundo crate's vtable POD (identical layout). +pub type Vtable = oakundo::undocommand::OakUndoCommandVtable; /// Rust closure state behind a vtable command's `userdata` pointer. /// @@ -130,11 +122,13 @@ pub fn command_init(vtable: &Vtable, userdata: *mut std::ffi::c_void) -> Option< /// `oakundo_command_init` (vtable command). #[cfg(not(feature = "test-stubs"))] pub fn command_init(vtable: &Vtable, userdata: *mut std::ffi::c_void) -> Option { - use crate::bridge::dlsym; - type F = unsafe extern "C" fn(*const Vtable, *mut std::ffi::c_void) -> CHandle; - dlsym::call::("oakundo_command_init", |f| unsafe { - f(vtable as *const Vtable, userdata) - }) + // Direct call into the oakundo crate (single-lib unification). + let h = unsafe { oakundo::ffi::command::oakundo_command_init(vtable, userdata) }; + if h.is_null() { + None + } else { + Some(h) + } } /// `oakundo_command_init_multi`. @@ -146,9 +140,13 @@ pub fn command_init_multi() -> Option { /// `oakundo_command_init_multi`. #[cfg(not(feature = "test-stubs"))] pub fn command_init_multi() -> Option { - use crate::bridge::dlsym; - type F = unsafe extern "C" fn() -> CHandle; - dlsym::call::("oakundo_command_init_multi", |f| unsafe { f() }) + // Direct call into the oakundo crate (single-lib unification). + let h = unsafe { oakundo::ffi::command::oakundo_command_init_multi() }; + if h.is_null() { + None + } else { + Some(h) + } } /// `oakundo_command_multi_add_child`. @@ -160,11 +158,8 @@ pub fn command_multi_add_child(multi: CHandle, child: CHandle) -> Option /// `oakundo_command_multi_add_child`. #[cfg(not(feature = "test-stubs"))] pub fn command_multi_add_child(multi: CHandle, child: CHandle) -> Option { - use crate::bridge::dlsym; - type F = unsafe extern "C" fn(CHandle, CHandle) -> c_int; - dlsym::call::("oakundo_command_multi_add_child", |f| unsafe { - f(multi, child) - }) + // Direct call into the oakundo crate (single-lib unification). + Some(unsafe { oakundo::ffi::command::oakundo_command_multi_add_child(multi, child) }) } /// `oakundo_command_redo_now`. @@ -176,9 +171,8 @@ pub fn command_redo_now(command: CHandle) -> Option { /// `oakundo_command_redo_now`. #[cfg(not(feature = "test-stubs"))] pub fn command_redo_now(command: CHandle) -> Option { - use crate::bridge::dlsym; - type F = unsafe extern "C" fn(CHandle) -> c_int; - dlsym::call::("oakundo_command_redo_now", |f| unsafe { f(command) }) + // Direct call into the oakundo crate (single-lib unification). + Some(unsafe { oakundo::ffi::command::oakundo_command_redo_now(command) }) } /// `oakundo_command_undo_now`. @@ -190,9 +184,8 @@ pub fn command_undo_now(command: CHandle) -> Option { /// `oakundo_command_undo_now`. #[cfg(not(feature = "test-stubs"))] pub fn command_undo_now(command: CHandle) -> Option { - use crate::bridge::dlsym; - type F = unsafe extern "C" fn(CHandle) -> c_int; - dlsym::call::("oakundo_command_undo_now", |f| unsafe { f(command) }) + // Direct call into the oakundo crate (single-lib unification). + Some(unsafe { oakundo::ffi::command::oakundo_command_undo_now(command) }) } /// `oakundo_command_free`. @@ -204,22 +197,14 @@ pub fn command_free(command: *mut CHandle) { /// `oakundo_command_free`. #[cfg(not(feature = "test-stubs"))] pub fn command_free(command: *mut CHandle) { - use crate::bridge::dlsym; - type F = unsafe extern "C" fn(*mut CHandle); - if let Some(f) = dlsym::call::("oakundo_command_free", |f| unsafe { - f(command) - }) { - let _ = f; - } + // Direct call into the oakundo crate (single-lib unification). + unsafe { oakundo::ffi::command::oakundo_command_free(command) } } /// `oakundo_stack_push` (facade-owned stack). pub fn stack_push(stack: CHandle, command: CHandle, text: *const std::ffi::c_char) -> Option { - use crate::bridge::dlsym; - type F = unsafe extern "C" fn(CHandle, CHandle, *const std::ffi::c_char) -> c_int; - dlsym::call::("oakundo_stack_push", |f| unsafe { - f(stack, command, text) - }) + // Direct call into the oakundo crate (single-lib unification). + Some(unsafe { oakundo::ffi::undostack::oakundo_undostack_push(stack, command, text) }) } /// In-crate implementations of the undo C ABI for `cargo test` diff --git a/src/node/rust/src/colormanager.rs b/src/node/rust/src/colormanager.rs index 154143ef6..cc893caa5 100644 --- a/src/node/rust/src/colormanager.rs +++ b/src/node/rust/src/colormanager.rs @@ -55,19 +55,11 @@ impl ColorManager { } /// Load the built-in default config (C++ `ColorManager::init()`). - /// The config load itself goes through the oakrender color C ABI; - /// when oakrender is absent (cargo test) the manager still marks the - /// config loaded with the built-in defaults so pure-graph consumers - /// can query state. + /// The oakrender color C ABI never exported the config-loading + /// symbols, so this always took the "mark loaded with the built-in + /// defaults" path (single-lib: the render call is removed and the + /// deterministic equivalent kept). pub fn initialize(&mut self) -> crate::error::Result<()> { - match crate::bridge::render::color_config_create_default() { - Some(Err(())) => { - return Err(crate::error::Error::Failed( - "OCIO config creation failed".to_string(), - )); - } - _ => {} - } self.config_loaded = true; Ok(()) } @@ -79,30 +71,18 @@ impl ColorManager { Ok(()) } - /// (Re)load the config from `config_filename` via the oakrender - /// color C ABI (`oakrender_color_manager_*`); E_FAILED on OCIO + /// (Re)load the config from `config_filename`; E_FAILED on OCIO /// errors. Missing/invalid files keep the previous config (C++ - /// `update_config_from_filename()`). + /// `update_config_from_filename()`). The oakrender color C ABI never + /// implemented the load, so the file-loaded path always kept the + /// previous state (single-lib: the render call is removed). pub fn update_config_from_filename(&mut self) -> crate::error::Result<()> { if self.config_filename.is_empty() { // Empty filename selects the bundled default. self.config_loaded = true; return Ok(()); } - match crate::bridge::render::color_config_load(&self.config_filename) { - Some(Ok(())) => { - self.config_loaded = true; - Ok(()) - } - Some(Err(())) => { - // Invalid file: keep the previous config (C++ tolerance). - Ok(()) - } - None => { - // oakrender absent (tests): keep the previous state. - Ok(()) - } - } + Ok(()) } /// Enumerate colorspaces of the active config (two-stage lists are diff --git a/src/node/rust/src/handle.rs b/src/node/rust/src/handle.rs index 10cb84585..e62c07da5 100644 --- a/src/node/rust/src/handle.rs +++ b/src/node/rust/src/handle.rs @@ -37,45 +37,12 @@ pub struct RefBox { pub value: T, } -/// `#[repr(C)]` mirror of the public handle structs -/// (`{ctx, addref, release, abi_version}`). -#[repr(C)] -#[derive(Clone, Debug)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -impl CHandle { - /// The empty handle. - pub fn null() -> Self { - Self { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: OAKNODE_ABI_VERSION, - } - } - - /// True when `ctx` is null. - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} - -// CHandle is the C-side value handle (passed by value, copyable across -// threads); `ctx` is an opaque box pointer. The addref/release functions -// are atomic, so sharing the box between threads is the host's -// dispatching contract (same rationale as the oakplugin crate's -// handle.rs). -unsafe impl Send for CHandle {} -unsafe impl Sync for CHandle {} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. +pub use oakcore_rs::handle::CHandle; /// addref 的实现:原子 +1。拥有型与借用型共用——借用型只延长盒子 /// 的寿命,不延长被借用对象。 diff --git a/src/node/rust/src/project.rs b/src/node/rust/src/project.rs index e06a8360b..0923fdf9b 100644 --- a/src/node/rust/src/project.rs +++ b/src/node/rust/src/project.rs @@ -311,11 +311,9 @@ impl Project { } _ => {} } - // Default location: ask oakrender via the C ABI. - match crate::bridge::render::disk_cache_path() { - Some(path) => path, - None => String::new(), - } + // Default location: the shared disk-cache directory (single-lib: + // lives in oakcommon, used by oaknode and oakrender alike). + oakcommon::filefunctions::default_disk_cache_path() } /// Copy all settings from `src` into `self` (C++ diff --git a/src/oakcore-rs/src/handle.rs b/src/oakcore-rs/src/handle.rs new file mode 100644 index 000000000..0bdb814ce --- /dev/null +++ b/src/oakcore-rs/src/handle.rs @@ -0,0 +1,95 @@ +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! The shared ABI value-handle type (single-lib unification). +//! +//! Every module crate used to define its own `CHandle` with an identical +//! `{ctx, addref, release, abi_version}` layout but a distinct Rust type, +//! so cross-module calls had to cross an `extern "C"`/dlsym boundary. +//! With the module-to-module calls going back to direct Rust calls (see +//! `docs/zh/plans/riir/single-lib.md`), one canonical handle type lives +//! here in `oakcore-rs` (the crate every module already depends on) and +//! every crate re-exports it. The C layout is unchanged, so the frozen +//! module C ABIs (`Oak*` handles in `include//*.h`) are +//! unaffected. + +use std::ffi::c_void; + +/// ABI value handle mirroring the C handle struct +/// (`{ctx, addref, release, abi_version}`) from `include/common/handle.h`. +/// +/// `ctx` points to an opaque refcounted box; `addref`/`release` are the +/// box's atomic increment/decrement (release destroys at zero); +/// `abi_version` is a tag stamped by each crate's `make_owned` (0 for +/// empty handles). Structurally identical to every `Oak` value +/// handle, so a handle can cross any module boundary by value. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct CHandle { + /// Opaque box pointer. + pub ctx: *mut c_void, + /// Atomic increment. + pub addref: Option, + /// Atomic decrement; destroys at zero. + pub release: Option, + /// ABI version. + pub abi_version: u32, +} + +impl CHandle { + /// The empty handle. + pub const fn null() -> Self { + CHandle { + ctx: std::ptr::null_mut(), + addref: None, + release: None, + abi_version: 0, + } + } /// Whether this is the empty (zero) handle. + pub fn is_null(&self) -> bool { + self.ctx.is_null() + } + + /// Take an additional reference through the handle's `addref` and + /// return the (now refcount-incremented) copy. + /// + /// # Safety + /// `self` must be a live handle returned by a module function. + pub unsafe fn addref(&self) -> Self { + let mut copy = *self; + if let Some(addref) = copy.addref { + let _ = &mut copy; + unsafe { + addref(copy.ctx); + } + } + copy + } +} + +/// The empty handle is the natural default (some crates derive `Default` +/// on structs holding a handle). +impl Default for CHandle { + fn default() -> Self { + Self::null() + } +} + +// Handles follow the shared_ptr-like convention of +// `include/common/handle.h`: they are opaque, refcounted and safe to +// share across threads (the module crates use them behind mutexes). +unsafe impl Send for CHandle {} +unsafe impl Sync for CHandle {} diff --git a/src/oakcore-rs/src/lib.rs b/src/oakcore-rs/src/lib.rs index bd6f17d73..c55913115 100644 --- a/src/oakcore-rs/src/lib.rs +++ b/src/oakcore-rs/src/lib.rs @@ -25,6 +25,10 @@ mod rational; mod samplefmt; mod timerange; +/// Shared ABI value-handle type (see [`handle::CHandle`]). +pub mod handle; + +pub use handle::CHandle; pub use rational::Rational; pub use samplefmt::{PixelFormat, SampleFormat}; pub use timerange::{TimeRange, TimeRangeList}; diff --git a/src/plugin/rust/Cargo.lock b/src/plugin/rust/Cargo.lock index f836d02bd..f37bfea15 100644 --- a/src/plugin/rust/Cargo.lock +++ b/src/plugin/rust/Cargo.lock @@ -18,11 +18,16 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" +[[package]] +name = "oakcore-rs" +version = "0.1.0" + [[package]] name = "oakplugin" version = "0.1.0" dependencies = [ "cc", + "oakcore-rs", ] [[package]] diff --git a/src/plugin/rust/Cargo.toml b/src/plugin/rust/Cargo.toml index 8d6392279..ec79b750b 100644 --- a/src/plugin/rust/Cargo.toml +++ b/src/plugin/rust/Cargo.toml @@ -17,7 +17,9 @@ crate-type = ["staticlib", "rlib"] panic = "unwind" [dependencies] +# 共享 ABI 类型(CHandle 等,单库化统一,见 docs/zh/plans/riir/single-lib.md)。 # 只允许零依赖起步。确需引入的 crate 必须在 README 登记理由。 +oakcore-rs = { path = "../../oakcore-rs" } [features] # oakrender 测试桩(库内 no_mangle 符号 + 状态访问器):cargo test diff --git a/src/plugin/rust/src/handle.rs b/src/plugin/rust/src/handle.rs index 8416a02a4..a211ea111 100644 --- a/src/plugin/rust/src/handle.rs +++ b/src/plugin/rust/src/handle.rs @@ -53,44 +53,12 @@ pub struct RefBox { /// C 句柄的 Rust 镜像。`#[repr(C)]`,与 C 头文件布局一致。 /// /// 生命周期:`*_init`/`*_create` 返回计数 1 的拥有型句柄; -/// `*_free(&h)` 释放一次并清空 `ctx`;`free(NULL)`/空句柄是 no-op。 -/// 值型(Clone/Copy:C 侧按值传句柄,复制后再 addref 是调用方 -/// 契约)。 -#[derive(Clone, Copy)] -#[repr(C)] -pub struct CHandle { - /// 不透明盒子指针(`RefBox` 擦型后的 `*mut c_void`)。 - pub ctx: *mut std::ffi::c_void, - /// 原子 +1。 - pub addref: Option, - /// 原子 -1,归零销毁。 - pub release: Option, - /// [`OAKPLUGIN_ABI_VERSION`]。 - pub abi_version: u32, -} - -// CHandle 是 C 侧值型句柄(按值传、可跨线程复制);`ctx` 是 -// 不透明盒子指针,跨线程搬运是宿主分发语义(multithread suite -// 允许插件线程回调任意 suite)。 -unsafe impl Send for CHandle {} -unsafe impl Sync for CHandle {} - -impl CHandle { - /// 空句柄(`ctx == NULL`)。 - pub fn null() -> Self { - Self { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: OAKPLUGIN_ABI_VERSION, - } - } - - /// 是否为空调用面(`ctx` 为空)。 - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. `Send + Sync` come from the shared type. +pub use oakcore_rs::handle::CHandle; /// addref 的实现:原子 +1。拥有型与借用型共用——借用型只延长盒子 /// 的寿命,不延长被借用对象。 diff --git a/src/render/rust/Cargo.lock b/src/render/rust/Cargo.lock index a639b2e27..c8659e473 100644 --- a/src/render/rust/Cargo.lock +++ b/src/render/rust/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "android_system_properties" version = "0.1.6" @@ -94,6 +100,12 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "cc" version = "1.4.2" @@ -163,6 +175,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -184,12 +205,28 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + [[package]] name = "find-msvc-tools" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -369,6 +406,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "tiff", +] + [[package]] name = "indexmap" version = "2.14.0" @@ -487,6 +537,12 @@ dependencies = [ "libc", ] +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + [[package]] name = "metal" version = "0.31.0" @@ -502,6 +558,26 @@ dependencies = [ "paste", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "naga" version = "25.0.1" @@ -546,6 +622,17 @@ dependencies = [ "libm", ] +[[package]] +name = "oakcommon" +version = "0.1.0" +dependencies = [ + "image", + "log", + "oakcore-rs", + "ocio-rs", + "quick-xml", +] + [[package]] name = "oakcore-rs" version = "0.1.0" @@ -554,6 +641,7 @@ version = "0.1.0" name = "oakrender" version = "0.1.0" dependencies = [ + "oakcommon", "oakcore-rs", "ocio-rs", "wgpu", @@ -671,6 +759,27 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.47" @@ -761,6 +870,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + [[package]] name = "slab" version = "0.4.12" @@ -890,6 +1005,20 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "unicode-ident" version = "1.0.24" @@ -973,6 +1102,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + [[package]] name = "wgpu" version = "25.0.2" @@ -1297,3 +1432,18 @@ dependencies = [ "quote", "syn 2.0.119", ] + +[[package]] +name = "zune-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/src/render/rust/Cargo.toml b/src/render/rust/Cargo.toml index a782a8faf..7df553b38 100644 --- a/src/render/rust/Cargo.toml +++ b/src/render/rust/Cargo.toml @@ -15,6 +15,7 @@ panic = "unwind" [dependencies] oakcore-rs = { path = "../../oakcore-rs" } +oakcommon = { path = "../../common/rust" } # wgpu: portable GPU backend (Metal/Vulkan/GL/DX12 in one safe API) — the # direct replacement for the C++ liboakgl2/liboakvulkan backend plugins. # Version 25 (2025 stable line); the only GPU dependency. diff --git a/src/render/rust/src/cancelatom.rs b/src/render/rust/src/cancelatom.rs index 9a13a955b..388b6cd50 100644 --- a/src/render/rust/src/cancelatom.rs +++ b/src/render/rust/src/cancelatom.rs @@ -16,79 +16,11 @@ //! The cancellation primitive (`olive::CancelAtom`): a thread-safe cancel //! flag shared between a render/encode caller and its worker. +//! +//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): the +//! implementation moved to oakcommon; this module re-exports it so the +//! render ffi's `oakrender_cancelatom_*` exports (and their C-ABI +//! consumers, e.g. oakcodec) keep working unchanged. -use std::sync::{Mutex, MutexGuard}; - -/// A cancellation atom (C++ `CancelAtom`). Reading a set flag also records -/// that a consumer heard the cancellation. -#[derive(Default)] -pub struct CancelAtom { - state: Mutex, -} - -#[derive(Default)] -struct AtomState { - cancelled: bool, - heard: bool, -} - -fn lock(m: &Mutex) -> MutexGuard<'_, AtomState> { - m.lock().unwrap_or_else(|e| e.into_inner()) -} - -impl CancelAtom { - /// A not-cancelled atom. - pub fn new() -> Self { - Self::default() - } - - /// Set the cancel flag (C++ `CancelAtom::cancel()`). - pub fn cancel(&self) { - lock(&self.state).cancelled = true; - } - - /// Read the cancel flag; reading a set flag records that the - /// cancellation was heard (C++ `is_cancelled()`). - pub fn is_cancelled(&self) -> bool { - let mut s = lock(&self.state); - if s.cancelled { - s.heard = true; - } - s.cancelled - } - - /// Whether any consumer has observed the cancel flag through - /// [`CancelAtom::is_cancelled`] (C++ `heard_cancel()`). - pub fn heard_cancel(&self) -> bool { - lock(&self.state).heard - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn fresh_atom_is_not_cancelled() { - let a = CancelAtom::new(); - assert!(!a.is_cancelled()); - assert!(!a.heard_cancel()); - } - - #[test] - fn cancel_sets_flag_and_reading_marks_heard() { - let a = CancelAtom::new(); - a.cancel(); - assert!(!a.heard_cancel(), "not heard until read"); - assert!(a.is_cancelled()); - assert!(a.heard_cancel(), "reading a set flag marks it heard"); - } - - #[test] - fn repeated_cancel_is_idempotent() { - let a = CancelAtom::new(); - a.cancel(); - a.cancel(); - assert!(a.is_cancelled()); - } -} +/// Shared cancellation atom (oakcommon). +pub use oakcommon::cancelatom::CancelAtom; diff --git a/src/render/rust/src/ffi.rs b/src/render/rust/src/ffi.rs index 865524d99..7cfe9f19c 100644 --- a/src/render/rust/src/ffi.rs +++ b/src/render/rust/src/ffi.rs @@ -926,13 +926,8 @@ pub mod cache { if !std::path::Path::new(&filename).exists() { return Err(crate::error::Error::NotFound); } - // Payload decode belongs to the oakcodec crate (EXR/JPEG). - // Without it the file exists but cannot be decoded. - if !crate::bridge::codec::codec_abi_available() { - return Err(crate::error::Error::Failed( - "oakcodec C ABI not present (frame decode pending)".into(), - )); - } + // Payload decode belongs to the oakcodec crate (EXR/JPEG), + // deferred; without it the file exists but cannot be decoded. Err(crate::error::Error::Failed( "oakcodec frame decode bridge pending".into(), )) diff --git a/src/render/rust/src/handle.rs b/src/render/rust/src/handle.rs index 63f46f9f0..baffa643d 100644 --- a/src/render/rust/src/handle.rs +++ b/src/render/rust/src/handle.rs @@ -42,42 +42,12 @@ pub struct RefBox { pub value: T, } -/// `#[repr(C)]` mirror of the public handle structs. -#[derive(Clone, Copy)] -#[repr(C)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -// CHandle is a by-value handle (copied across threads per the shared_ptr -// semantics documented in the public headers); `ctx` is an opaque box -// pointer, and moving the struct itself never dereferences it. -unsafe impl Send for CHandle {} -unsafe impl Sync for CHandle {} - -impl CHandle { - /// The empty handle. - pub fn null() -> Self { - Self { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: OAKRENDER_ABI_VERSION, - } - } - - /// True when `ctx` is null. - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. `Send + Sync` come from the shared type. +pub use oakcore_rs::handle::CHandle; /// Global live-object count (owned handles + cancel-atom boxes). static ALIVE_COUNT: AtomicUsize = AtomicUsize::new(0); diff --git a/src/render/rust/src/manager.rs b/src/render/rust/src/manager.rs index 769cb11b0..64a34fbf0 100644 --- a/src/render/rust/src/manager.rs +++ b/src/render/rust/src/manager.rs @@ -132,9 +132,10 @@ impl RenderManager { } /// The default disk cache directory (C++ `DiskManager:: -/// get_default_disk_cache_path`). +/// get_default_disk_cache_path`); shared with oaknode via oakcommon +/// (single-lib unification). pub fn disk_cache_path() -> String { - crate::bridge::common::default_disk_cache_path() + oakcommon::filefunctions::default_disk_cache_path() } /// Bytes consumed by the default disk cache folder (direct filesystem diff --git a/src/task/rust/Cargo.lock b/src/task/rust/Cargo.lock index 77bfb242e..c35d99fbd 100644 --- a/src/task/rust/Cargo.lock +++ b/src/task/rust/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "android_system_properties" version = "0.1.6" @@ -94,6 +100,12 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "cc" version = "1.4.2" @@ -163,6 +175,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -184,12 +205,28 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + [[package]] name = "find-msvc-tools" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -369,6 +406,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "tiff", +] + [[package]] name = "indexmap" version = "2.14.0" @@ -514,6 +564,26 @@ dependencies = [ "paste", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "naga" version = "25.0.1" @@ -558,6 +628,17 @@ dependencies = [ "libm", ] +[[package]] +name = "oakcommon" +version = "0.1.0" +dependencies = [ + "image", + "log", + "oakcore-rs", + "ocio-rs", + "quick-xml", +] + [[package]] name = "oakcore-rs" version = "0.1.0" @@ -576,6 +657,7 @@ dependencies = [ name = "oakrender" version = "0.1.0" dependencies = [ + "oakcommon", "oakcore-rs", "ocio-rs", "wgpu", @@ -702,6 +784,18 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.41.0" @@ -815,6 +909,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + [[package]] name = "slab" version = "0.4.12" @@ -944,6 +1044,20 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "unicode-ident" version = "1.0.24" @@ -1027,6 +1141,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + [[package]] name = "wgpu" version = "25.0.2" @@ -1357,3 +1477,18 @@ name = "zmij" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zune-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/src/task/rust/src/handle.rs b/src/task/rust/src/handle.rs index aadfbf1a7..72a843e02 100644 --- a/src/task/rust/src/handle.rs +++ b/src/task/rust/src/handle.rs @@ -33,29 +33,12 @@ pub struct RefBox { pub value: T, } -/// `#[repr(C)]` mirror of the public handle structs -/// (`{ctx, addref, release, abi_version}`). -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -// Handles are shared between the calling thread and the manager worker -// threads (same ownership model as a C++ shared_ptr). The raw pointer and -// function-pointer fields are inherently `!Send`/`!Sync`; the box behind -// `ctx` is either `Send + Sync` (task state, atomics) or a plain pointer -// (borrowed handles), both of which are safe to share through the -// refcounted handle. -unsafe impl Send for CHandle {} -unsafe impl Sync for CHandle {} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. `Send + Sync` come from the shared type. +pub use oakcore_rs::handle::CHandle; unsafe extern "C" fn noop_addref(_ctx: *mut std::ffi::c_void) {} @@ -101,24 +84,6 @@ unsafe extern "C" fn borrowed_release(ctx: *mut std::ffi::c_void) { } } -impl CHandle { - /// The empty handle. `ctx` is null but the fn pointers and ABI version - /// are stamped so callers can unconditionally call `release`. - pub fn null() -> Self { - CHandle { - ctx: std::ptr::null_mut(), - addref: Some(noop_addref), - release: Some(noop_release), - abi_version: OAKTASK_ABI_VERSION, - } - } - - /// Whether the handle is empty (`ctx == NULL`). - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} - /// Owned handle with count 1; empty on allocation failure. pub fn make_owned(value: T) -> CHandle { let b = Box::new(RefBox { refs: AtomicU32::new(1), value }); diff --git a/src/task/rust/tests/bridge_test.rs b/src/task/rust/tests/bridge_test.rs index 35ed336f8..1d910c5a2 100644 --- a/src/task/rust/tests/bridge_test.rs +++ b/src/task/rust/tests/bridge_test.rs @@ -53,20 +53,15 @@ fn abi_version_is_one() { assert_eq!(OAKTASK_ABI_VERSION, 1); } -/// Given a null handle, `CHandle::null()` has a null ctx, non-null -/// addref/release, and the stamped ABI version. +/// Given a null handle, `CHandle::null()` has a null ctx, no addref/ +/// release fn pointers and no ABI version (single-lib unification). #[test] fn null_handle_contract() { let h = CHandle::null(); assert!(h.ctx.is_null()); - assert!(h.addref.is_some(), "null handle addref must be callable"); - assert!(h.release.is_some(), "null handle release must be callable"); - assert_eq!(h.abi_version, OAKTASK_ABI_VERSION); - // The empty handle is a no-op for both ops (never touches memory). - unsafe { - h.addref.unwrap()(h.ctx); - h.release.unwrap()(h.ctx); - } + assert!(h.addref.is_none(), "null handle addref is empty"); + assert!(h.release.is_none(), "null handle release is empty"); + assert_eq!(h.abi_version, 0); // `is_null` reflects the ctx. assert!(h.is_null()); } @@ -91,7 +86,11 @@ fn handle_size_and_owned_release() { } // The boxed value was dropped; a null handle still works afterwards. let null_h = CHandle::null(); - unsafe { - null_h.release.unwrap()(null_h.ctx); + // The shared null() carries no fn pointers; releasing goes through + // the `if let Some` path (a no-op for empty handles). + if let Some(release) = null_h.release { + unsafe { + release(null_h.ctx); + } } } diff --git a/src/timeline/rust/src/handle.rs b/src/timeline/rust/src/handle.rs index ba3d443d8..86b2fccbc 100644 --- a/src/timeline/rust/src/handle.rs +++ b/src/timeline/rust/src/handle.rs @@ -38,20 +38,12 @@ pub struct RefBox { pub value: T, } -/// `#[repr(C)]` mirror of the public handle structs -/// (`{ctx, addref, release, abi_version}`). -#[repr(C)] -#[derive(Clone)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. +pub use oakcore_rs::handle::CHandle; /// Generic `addref` implementation: increments the box's reference count. /// @@ -82,23 +74,6 @@ unsafe extern "C" fn release_box(ptr: *mut c_void) { } } -impl CHandle { - /// The empty handle. - pub fn null() -> Self { - CHandle { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: 0, - } - } - - /// Whether this is the empty (all-null) handle. - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} - /// Owned handle with count 1; empty on allocation failure. pub fn make_owned(value: T) -> CHandle { let boxed = Box::new(RefBox { diff --git a/src/undo/rust/src/ffi.rs b/src/undo/rust/src/ffi.rs index f24341102..5c3495b1d 100644 --- a/src/undo/rust/src/ffi.rs +++ b/src/undo/rust/src/ffi.rs @@ -48,63 +48,14 @@ use crate::undostack::UndoStack; /// [`crate::handle`]. /// `include/undo/undocommand.h` handle type — `OakUndoCommand` -/// (`{ctx, addref, release, abi_version}`). -#[repr(C)] -#[derive(Clone, Copy)] -pub struct OakUndoCommand { - /// Opaque box pointer. - pub ctx: *mut c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// OAKUNDO_ABI_VERSION. - pub abi_version: u32, -} +/// (`{ctx, addref, release, abi_version}`). Single-lib unification: +/// aliases the shared [`CHandle`] (identical layout; the C ABI is +/// unchanged). +pub type OakUndoCommand = CHandle; -/// `include/undo/undostack.h` handle type — `OakUndoStack`. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct OakUndoStack { - /// Opaque box pointer. - pub ctx: *mut c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// OAKUNDO_ABI_VERSION. - pub abi_version: u32, -} - -/// Field-copy [`OakUndoStack`] into a [`CHandle`]. -fn chandle_from_stack(stack: OakUndoStack) -> CHandle { - CHandle { - ctx: stack.ctx, - addref: stack.addref, - release: stack.release, - abi_version: stack.abi_version, - } -} - -/// Field-copy a [`CHandle`] into an [`OakUndoStack`]. -fn stack_from_chandle(handle: CHandle) -> OakUndoStack { - OakUndoStack { - ctx: handle.ctx, - addref: handle.addref, - release: handle.release, - abi_version: handle.abi_version, - } -} - -/// Field-copy a [`CHandle`] into an [`OakUndoCommand`]. -fn command_from_chandle(handle: CHandle) -> OakUndoCommand { - OakUndoCommand { - ctx: handle.ctx, - addref: handle.addref, - release: handle.release, - abi_version: handle.abi_version, - } -} +/// `include/undo/undostack.h` handle type — `OakUndoStack`. Single-lib +/// unification: aliases the shared [`CHandle`]. +pub type OakUndoStack = CHandle; /// Lock the stack behind `stack` and run `f` on it. `E_INVALID` for an /// empty handle. A poisoned mutex is recovered (its inner value is @@ -112,7 +63,7 @@ fn command_from_chandle(handle: CHandle) -> OakUndoCommand { fn with_stack(stack: OakUndoStack, f: impl FnOnce(&mut UndoStack) -> Result) -> Result { // Keep a local handle so `get`'s returned reference lives for the // whole call (its lifetime ties to the `&CHandle` argument). - let ch = chandle_from_stack(stack); + let ch = stack; let m = unsafe { crate::handle::get::>(&ch) }.ok_or(Error::Invalid)?; let mut guard = m.lock().unwrap_or_else(|e| e.into_inner()); f(&mut guard) @@ -143,21 +94,21 @@ pub mod command { vtable: *const OakUndoCommandVtable, userdata: *mut c_void, ) -> OakUndoCommand { - command_from_chandle(guard_handle(|| unsafe { + guard_handle(|| unsafe { if vtable.is_null() { return Ok(CHandle::null()); } let table = *vtable; Ok(command_from_owned(UndoCommand::from_vtable(table, userdata))) - })) + }) } /// `oakundo_command_init_multi`: empty multi command, refcount 1. #[no_mangle] pub unsafe extern "C" fn oakundo_command_init_multi() -> OakUndoCommand { - command_from_chandle(guard_handle(|| unsafe { + guard_handle(|| unsafe { Ok(command_from_owned(UndoCommand::multi())) - })) + }) } /// `oakundo_command_multi_add_child` (stack takes one child ref). @@ -216,7 +167,7 @@ pub mod command { } let child = parent.multi_child(index as usize)?; let ptr = child as *const UndoCommand as *mut UndoCommand; - *out_child = command_from_chandle(command_from_borrowed(ptr)); + *out_child = command_from_borrowed(ptr); Ok(()) }) } @@ -272,9 +223,9 @@ pub mod undostack { /// `oakundo_undostack_init`: fresh stack, refcount 1. #[no_mangle] pub unsafe extern "C" fn oakundo_undostack_init() -> OakUndoStack { - stack_from_chandle(guard_handle(|| { + guard_handle(|| { Ok(make_owned(Mutex::new(UndoStack::new()))) - })) + }) } /// `oakundo_undostack_free`: NULL/empty no-op; clears `stack->ctx`. diff --git a/src/undo/rust/src/handle.rs b/src/undo/rust/src/handle.rs index 099a6b785..fe563ab78 100644 --- a/src/undo/rust/src/handle.rs +++ b/src/undo/rust/src/handle.rs @@ -34,36 +34,12 @@ pub struct RefBox { pub value: T, } -/// `#[repr(C)]` mirror of the public handle structs -/// (`{ctx, addref, release, abi_version}`). -#[repr(C)] -pub struct CHandle { - /// Opaque box pointer. - pub ctx: *mut std::ffi::c_void, - /// Atomic increment. - pub addref: Option, - /// Atomic decrement; destroys at zero. - pub release: Option, - /// ABI version. - pub abi_version: u32, -} - -impl CHandle { - /// The empty handle. - pub fn null() -> Self { - CHandle { - ctx: std::ptr::null_mut(), - addref: None, - release: None, - abi_version: 0, - } - } - - /// Whether this is the empty (zero) handle. - pub fn is_null(&self) -> bool { - self.ctx.is_null() - } -} +/// The shared ABI value-handle type (single-lib unification, see +/// `docs/zh/plans/riir/single-lib.md`): one canonical +/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported +/// here so the crate's `ffi.rs` signatures and handle scaffolding stay +/// source-compatible. +pub use oakcore_rs::handle::CHandle; /// Owned handle with count 1; empty on allocation failure. pub fn make_owned(value: T) -> CHandle { diff --git a/src/undo/rust/tests/ffi_contract_test.rs b/src/undo/rust/tests/ffi_contract_test.rs index d45fa17a8..1bb948da7 100644 --- a/src/undo/rust/tests/ffi_contract_test.rs +++ b/src/undo/rust/tests/ffi_contract_test.rs @@ -38,6 +38,7 @@ use oakundo::ffi::undostack::{ oakundo_undostack_redo, oakundo_undostack_undo, }; use oakundo::ffi::{OakUndoCommand, OakUndoStack}; +use oakundo::handle::CHandle; use oakundo::handle::OAKUNDO_ABI_VERSION; use oakundo::undocommand::OakUndoCommandVtable; @@ -103,7 +104,7 @@ unsafe fn make_cmd(probe: *mut Probe) -> OakUndoCommand { /// An empty (all-zero) command handle. fn empty_cmd() -> OakUndoCommand { - OakUndoCommand { + CHandle { ctx: std::ptr::null_mut(), addref: None, release: None, @@ -113,7 +114,7 @@ fn empty_cmd() -> OakUndoCommand { /// An empty (all-zero) stack handle. fn empty_stack() -> OakUndoStack { - OakUndoStack { + CHandle { ctx: std::ptr::null_mut(), addref: None, release: None,