ワンクリックで
ffi
Rust FFI Best Practices guidance for Fortress Rollback. Use when Writing FFI code, C interop, bindgen usage.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Rust FFI Best Practices guidance for Fortress Rollback. Use when Writing FFI code, C interop, bindgen usage.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Crate Publishing guidance for Fortress Rollback. Use when Publishing to crates.io, version bumps, release checklist.
Changelog Practices guidance for Fortress Rollback. Use when Writing CHANGELOG entries, deciding what to document.
Design Decision Log Pattern guidance for Fortress Rollback. Use when Architectural decisions, design alternatives, superseding prior choices.
Repository-wide engineering policy and project context for Fortress Rollback. Use when implementing, diagnosing, reviewing, testing, documenting, or releasing changes in this repository.
GitHub Actions Best Practices guidance for Fortress Rollback. Use when Writing GitHub Actions workflows, CI debugging, actionlint, caching.
Workspace Organization guidance for Fortress Rollback. Use when Organizing workspace, splitting crates, module structure decisions.
| name | ffi |
| description | Rust FFI Best Practices guidance for Fortress Rollback. Use when Writing FFI code, C interop, bindgen usage. |
Good candidates: Leaf libraries, parsers, modules processing untrusted data, media handling. Avoid converting: Battle-tested crypto, code without allocation, long-stable code. Problematic: Complex OOP hierarchies, Qt apps, template-heavy code.
| Tool | Direction | Best For |
|---|---|---|
extern "C" | Both | Simple C functions |
bindgen | C/C++ -> Rust | Consuming C libraries |
cbindgen | Rust -> C/C++ | Exposing Rust to C |
CXX | Bidirectional | Safe interop with type restrictions |
AutoCXX | C++ -> Rust | Existing C++ APIs |
UniFFI | Rust -> Many | Mobile (Swift/Kotlin) |
PyO3 | Rust <-> Python | Python extensions |
#[no_mangle]
pub unsafe extern "C" fn process_string(input: *const c_char) -> c_int {
if input.is_null() { return -1; }
let c_str = match CStr::from_ptr(input).to_str() {
Ok(s) => s,
Err(_) => return -2,
};
0 // success
}
pub struct GameEngine { /* fields */ }
#[no_mangle]
pub extern "C" fn engine_create() -> *mut GameEngine {
Box::into_raw(Box::new(GameEngine::new()))
}
#[no_mangle]
pub unsafe extern "C" fn engine_destroy(handle: *mut GameEngine) {
if !handle.is_null() { drop(Box::from_raw(handle)); }
}
Treat the Rust/C++ boundary like a service boundary. Don't share memory; exchange messages.
| Pattern | Rule |
|---|---|
| Rust creates, C borrows | Rust retains ownership; C must not store pointer |
| Rust creates, C takes ownership | C must call Rust's free function |
| C creates, Rust uses | Rust must not free; document lifetime |
| Shared data | Reference counting or explicit sync |
#[repr(C)]
pub enum ErrorCode {
Success = 0, NullPointer = -1, InvalidUtf8 = -2,
InvalidArgument = -3, OutOfMemory = -4, Unknown = -255,
}
thread_local! { static LAST_ERROR: RefCell<Option<CString>> = RefCell::new(None); }
#[no_mangle]
pub extern "C" fn get_last_error() -> *const c_char {
LAST_ERROR.with(|e| e.borrow().as_ref().map_or(ptr::null(), |s| s.as_ptr()))
}
#[no_mangle]
pub extern "C" fn safe_function() -> ErrorCode {
// Closure must be UnwindSafe; AssertUnwindSafe opts in when you've verified safety
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { /* logic */ })) {
Ok(result) => result,
Err(_) => ErrorCode::Unknown,
}
}
#[cxx::bridge]
mod ffi {
struct GameConfig { width: u32, height: u32, fullscreen: bool }
extern "Rust" {
type GameEngine;
fn create_engine(config: GameConfig) -> Box<GameEngine>;
}
unsafe extern "C++" {
include!("renderer.h");
type Renderer;
fn render_frame(renderer: &Renderer, data: &[u8]);
}
}
// build.rs: panic is appropriate for build failures
cbindgen::Builder::new()
.with_crate(&crate_dir)
.with_language(cbindgen::Language::C)
.generate().unwrap()
.write_to_file("include/my_lib.h");
// build.rs: panic is appropriate for build failures
bindgen::Builder::default()
.header("wrapper.h")
.generate().unwrap()
.write_to_file(out_path.join("bindings.rs")).unwrap();
[lib]
crate-type = ["cdylib", "staticlib", "lib"]
lto = true in release profile + CC=clangunsafe blocks justified and minimal