Files
oak-editor/crates/oakcore/src/handle.rs
T
Mike-Solar 18ff60f147 feat(engine): clip move, clip effect_input, mandatory static FFmpeg
- oakengine_sequence_move_clip implemented for real (oaktimeline
  TrackMoveBlockCommand; fixes the graph-ownership/gap-anchor/ripple
  trim bugs the stub was hiding); same-track via the frozen C ABI,
  cross-track supported by the module command
- oaknode clip blocks now declare a tex_in texture input and set
  effect_input to it, so timeline clips can host effect chains; facade
  test covers effect insert/remove on a real clip
- oakffmpeg-link: FFMPEG_DIR is now mandatory with a clear panic (a
  Homebrew upgrade left the system ffmpeg .pc pointing at a deleted
  dav1d Cellar path, breaking links); reads a git-ignored workspace
  .env for IDEs that cannot inject env vars (RustRover); links the C++
  stdlib for C++ codec libs (svt-av1)
- oakengine re-exports oaknode so tests share one crate instance;
  it_node uses the direct instance's value type where it calls the
  module FFI (the --workspace dev-dependency feature split builds
  oaknode twice)
2026-08-11 23:04:48 +08:00

97 lines
3.3 KiB
Rust

// 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 <http://www.gnu.org/licenses/>.
//! 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<Mod><Type>*` handles in `include/<mod>/*.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<Mod><Type>` value
/// handle, so a handle can cross any module boundary by value.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CHandle {
/// Opaque box pointer.
pub ctx: *mut c_void,
/// Atomic increment.
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
/// Atomic decrement; destroys at zero.
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
/// 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 {}