From f12cf3ffef35c4536c2e7787d24cf2ef852e88d5 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Tue, 18 Aug 2026 21:40:22 +0800 Subject: [PATCH] refactor(oakundo): mark raw-pointer facade functions unsafe Part of the CHandle/unsafe cleanup: can_undo/can_redo/command_text/ command_is_done and command_init take raw pointers and are now unsafe fn, with call sites wrapped in explicit unsafe blocks. --- crates/oakundo/src/global.rs | 19 ++++++++++--------- crates/oakundo/src/undocommand.rs | 8 ++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/oakundo/src/global.rs b/crates/oakundo/src/global.rs index 055591b76..ec9c38356 100644 --- a/crates/oakundo/src/global.rs +++ b/crates/oakundo/src/global.rs @@ -237,7 +237,7 @@ pub fn push(command: UndoCommand, name: &str) -> Result<()> { return Err(Error::NoMem); } let rc = push_or_run(handle, name); - command_free(&mut handle); + unsafe{command_free(&mut handle)}; if rc == 0 { Ok(()) } else { @@ -262,13 +262,13 @@ pub fn redo() -> Result<()> { /// Whether the process-wide stack has an entry to undo. pub fn undoable() -> bool { let mut v: c_int = 0; - can_undo(&mut v).is_ok() && v != 0 + unsafe{can_undo(&mut v).is_ok() && v != 0} } /// Whether the process-wide stack has an entry to redo. pub fn redoable() -> bool { let mut v: c_int = 0; - can_redo(&mut v).is_ok() && v != 0 + unsafe{can_redo(&mut v).is_ok() && v != 0} } // --------------------------------------------------------------------------- @@ -287,7 +287,7 @@ pub fn index() -> Result { /// Whether an undo is possible (1/0 via `out_value`; a module error code /// otherwise). -pub fn can_undo(out_value: *mut c_int) -> Result<()> { +pub unsafe fn can_undo(out_value: *mut c_int) -> Result<()> { if out_value.is_null() { return Err(Error::Invalid); } @@ -300,7 +300,7 @@ pub fn can_undo(out_value: *mut c_int) -> Result<()> { /// Whether a redo is possible (1/0 via `out_value`; a module error code /// otherwise). -pub fn can_redo(out_value: *mut c_int) -> Result<()> { +pub unsafe fn can_redo(out_value: *mut c_int) -> Result<()> { if out_value.is_null() { return Err(Error::Invalid); } @@ -334,7 +334,7 @@ pub fn clear() -> Result<()> { /// Two-stage label getter for the row at `row` (see /// [`crate::undostack::undostack_command_text`]): returns the required /// size including the NUL, or a module error code. -pub fn command_text(row: i64, buf: *mut c_char, buf_size: c_int) -> c_int { +pub unsafe fn command_text(row: i64, buf: *mut c_char, buf_size: c_int) -> c_int { let result = catch_unwind(AssertUnwindSafe(|| -> Result { with_stack(|s| { if row < 0 || row >= s.command_count() { @@ -364,7 +364,7 @@ pub fn command_text(row: i64, buf: *mut c_char, buf_size: c_int) -> c_int { /// Whether the row at `row` is done (1/0 via `out_value`; a module error /// code otherwise — `-20004` for an out-of-range row). -pub fn command_is_done(row: i64, out_value: *mut c_int) -> Result<()> { +pub unsafe fn command_is_done(row: i64, out_value: *mut c_int) -> Result<()> { if out_value.is_null() { return Err(Error::Invalid); } @@ -411,6 +411,7 @@ mod tests { fn vtable_command() -> CHandle { use crate::undocommand::{command_init, OakUndoCommandVtable}; + unsafe{ command_init( &OakUndoCommandVtable { redo: None, @@ -418,7 +419,7 @@ mod tests { free_fn: None, }, std::ptr::null_mut(), - ) + )} } #[test] @@ -431,7 +432,7 @@ mod tests { assert_eq!(count().unwrap(), 1); assert_eq!(index().unwrap(), 1); let mut v: c_int = 1; - assert!(can_undo(&mut v).is_ok()); + assert!(unsafe{can_undo(&mut v).is_ok()}); assert_eq!(v, 0); // Push fires the observer once. diff --git a/crates/oakundo/src/undocommand.rs b/crates/oakundo/src/undocommand.rs index fb018a0de..aee517685 100644 --- a/crates/oakundo/src/undocommand.rs +++ b/crates/oakundo/src/undocommand.rs @@ -565,7 +565,7 @@ pub(crate) unsafe extern "C" fn command_release(ctx: *mut c_void) { /// Create a vtable-backed command handle (refcount 1); a `NULL` vtable /// yields an empty handle (`oakundo_command_init`). -pub fn command_init(vtable: *const OakUndoCommandVtable, userdata: *mut c_void) -> CHandle { +pub unsafe fn command_init(vtable: *const OakUndoCommandVtable, userdata: *mut c_void) -> CHandle { guard_handle(|| unsafe { if vtable.is_null() { return Ok(CHandle::null()); @@ -598,7 +598,7 @@ pub fn command_multi_add_child(multi: CHandle, child: CHandle) -> c_int { /// Number of children of a multi command handle; `E_INVALID` for an /// empty handle or a non-multi parent (`oakundo_command_multi_child_count`). -pub fn command_multi_child_count(multi: CHandle, out_count: *mut c_int) -> c_int { +pub unsafe fn command_multi_child_count(multi: CHandle, out_count: *mut c_int) -> c_int { guard(|| unsafe { if out_count.is_null() { return Err(Error::Invalid); @@ -615,7 +615,7 @@ pub fn command_multi_child_count(multi: CHandle, out_count: *mut c_int) -> c_int /// Write a borrowed handle to the child at `index` of a multi command /// (the returned handle carries its own shell ref); `E_NOT_FOUND` for /// an out-of-range index (`oakundo_command_multi_child`). -pub fn command_multi_child(multi: CHandle, index: c_int, out_child: *mut CHandle) -> c_int { +pub unsafe fn command_multi_child(multi: CHandle, index: c_int, out_child: *mut CHandle) -> c_int { guard(|| unsafe { if out_child.is_null() { return Err(Error::Invalid); @@ -657,7 +657,7 @@ pub fn command_undo_now(command: CHandle) -> c_int { /// Release a command handle in place: run the release callback, then /// clear `ctx`. `NULL` / empty handles are no-ops /// (`oakundo_command_free`). -pub fn command_free(command: *mut CHandle) { +pub unsafe fn command_free(command: *mut CHandle) { guard_void(|| unsafe { if command.is_null() || (*command).ctx.is_null() { return;