Przejdź do treści
Biblioteka skilli
Programowanie · Budowanie i kod

rust-ffi

/rust-ffi

Projektuje granicę FFI w Ruście: cienką warstwę tłumaczącą, brak paniki przez granicę i jawną własność wskaźników.

Repozytorium
skills ↗
Licencja
BSD-3-Clause
Ostatnia zmiana repozytorium
16.08.2026

Ocena i bezpieczeństwo

95/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść30 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
2
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
0
Przestarzałość

Brak sygnałów. Repozytorium zmienione 16.08.2026, bez odwołań do wycofanych modeli i API.

Licencja

BSD-3-Clause, otwarta.

Co robi i kiedy

Projektuje granicę FFI w Ruście: cienką warstwę tłumaczącą, brak paniki przez granicę i jawną własność wskaźników.

Oryginalny opis (EN)

Design an FFI boundary meant to last — a thin translation layer with the logic in core crates, no panic across the boundary, explicit ownership on every pointer, repr(transparent) newtypes, and unsafe extern in edition 2024. Use when designing or reviewing a Rust FFI surface, when exposing a Rust library to another language, when a DLL or shared library keeps state, or when the user asks how to shape an extern function.

Jak działa

  1. The layer only translates
  2. Nothing panics across the boundary
  3. Every pointer states its ownership
  4. repr is part of the contract
  5. Isolate the state a shared library keeps
  6. Naming across the boundary
  7. The edition 2024 forms
  8. Strings and slices do not cross as they are
  9. Deferrals
  10. Verification
Sekcje z nagłówków SKILL.md, w oryginale · 119 linii, 708 słów
Podgląd SKILL.md
---
name: rust-ffi
description: Design an FFI boundary meant to last — a thin translation layer with the logic in core crates, no panic across the boundary, explicit ownership on every pointer, repr(transparent) newtypes, and unsafe extern in edition 2024. Use when designing or reviewing a Rust FFI surface, when exposing a Rust library to another language, when a DLL or shared library keeps state, or when the user asks how to shape an extern function.
---

# Rust FFI

A boundary that is meant to stay is designed, not discovered. Moving off C —
bindgen, cbindgen, and the link into an existing build — is `/port-from-c`.

## The layer only translates

Every line of business logic lives in a normal Rust crate that knows nothing
about FFI; the `extern` layer converts types, checks pointers, and calls in.
The core crate is testable with `cargo test`, the FFI layer only through a
foreign harness — logic that drifts into the boundary is logic no test reaches.

```rust
use std::ffi::{c_char, CStr};
use std::panic::catch_unwind;

// Core: the logic, in code that knows nothing about FFI.
pub struct Client {
    pub name: String,
}

impl Client {
    fn new(name: &str) -> Self {
        Client { name: name.to_owned() }
    }
}

// Boundary: translates, checks, and calls in — nothing else.
#[repr(transparent)]
pub struct MylibClient(*mut Client);

/// # Safety
/// `name` must be NUL-terminated UTF-8, or null; the check happens once,
/// here, on the way in.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mylib_client_new(name: *const c_char) -> *mut MylibClient {
    let build = || {
        if name.is_null() { return None; }
        let name = unsafe { CStr::from_ptr(name) }.to_str().ok()?;
        Some(Box::into_raw(Box::new(Client::new(name))) as *mut MylibClient)
    };
    catch_unwind(build).ok().flatten().unwrap_or(std::ptr::null_mut())
}

/// # Safety
/// `client` must be a non-null handle from `mylib_client_new`, freed exactly once.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mylib_client_free(client: *mut MylibClient) {
    drop(unsafe { Box::from_raw(client as *mut Client) });
}
```

## Nothing panics across the boundary

Unwinding into a foreign frame is undefined behaviour. Every `extern "C"`
entry point catches — `catch_unwind` at the boundary, and only there — and
converts the panic to an error code or an out-parameter, the one place
`/rust-errors` does not call `catch_unwind` a last resort.

## Every pointer states its ownership

Who allocated it, who frees it, how long it stays valid, and whether null is
allowed — in the signature and in the docs. A crate that exposes an
allocation exposes the matching free from the same crate; the other side
cannot free what the first side allocated. A `# Safety` section carries it —
`/rust-docs` for the wording, `/unsafe-rust` for the invariant.

## `repr` is part of the contract

`#[repr(C)]` on every struct that crosses, and `#[repr(transparent)]` on a
newtype that wraps a handle, so the wrapper is invisible on the wire and the
type safety is free on the Rust side. A default-`repr` struct has no layout
guarantee; code that reads it from the other side works until it does not.

## Isolate the state a shared library keeps

A DLL loaded twice, or loaded and unloaded, must not leave process-global
state behind. Prefer an opaque handle the caller creates, passes back, and
destroys, over module-level statics — the handle makes the lifetime explicit
and makes two instances possible.

## Naming across the boundary

Exported symbols are prefixed with the library name, because the C namespace
is flat: `mylib_client_new`, `mylib_client_free`. Inside Rust the same
function is `Client::new`; the prefix belongs to the exported symbol.

## The edition 2024 forms

`unsafe extern { }` around the declaration of a foreign function, and
`#[unsafe(no_mangle)]` on an export. Both say out loud what was always true:
declaring a foreign signature is an unsafe assertion about the other side.

## Strings and slices do not cross as they are

A Rust `&str` is not a C string, and a `String` cannot be freed by `free()`.
`CStr` and `CString` at the boundary, pointer-plus-length for slices, and the
UTF-8 validation happens once, explicitly, on the way in.

## Deferrals

Migrating an existing C codebase into Rust is `/port-from-c`, and the bindgen
and cbindgen walkthroughs live there. Whether an `unsafe` block is sound is
`/unsafe-rust`. What the safe Rust API on top should look like is
`/rust-api-design`. The `# Safety` section wording is `/rust-docs`.

## Verification

```bash
cargo test                   # the core crate, which holds the logic
cargo miri test              # for the Rust side of pointer handling that miri can see
cargo clippy --all-targets   # at the level the repo configures
```

Plus the boundary check no cargo command performs: a foreign-language test
that loads the library, exercises create-use-destroy, and runs under the
platform leak checker. An FFI surface without it is checked on one side only.
Pliki w paczce (2)
  • SKILL.md 5 KB
  • agents/openai.yaml 1 KB

Wersje

RepozytoriumWynikLicencja
Ta strona · rewrite-rs/skills95BSD-3-Clause
OutlineDriven/outline-driven-development100Apache-2.0
mohitmishra786/low-level-dev-skills100MIT

Migawka bazy z 28.10.2026 · wersja paczki bc1c29ec6485 (skrót SHA-256 całej paczki)

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100ffi-code-review
    Przegląda kod Rust FFI pod kątem bezpieczeństwa typów, układu pamięci, obsługi stringów, callbacków i poprawności granicy unsafe przy wywołaniach bibliotek C i C++.
  • 90analyze-rust-ffi-crate-surface
    Ustala, które części kodu C używają symboli zdefiniowanych w Rust, by ocenić wpływ zmian w skrzyni FFI na pliki C.
  • 100test-ffi-surface
    Buduje i testuje powierzchnię FFI NeMo Relay: zmiany w crates/ffi, generowanie nagłówków i walidację ABI.
  • 90minimize-rust-ffi-crate-surface
    Usuwa nieużywane symbole C zdefiniowane w Ruście, także te używane tylko w testach jednostkowych C lub C++, przy refaktoryzacji crate FFI.
  • 90ffi-boundaries
    Pomaga projektować granice wywołań obcych funkcji z jawną własnością, tłumaczeniem błędów i opanowanymi panikami lub wyjątkami, przy wiązaniach Rust, Go i Python z bibliotekami C i C++ albo udostępnianiu biblioteki przez C ABI.
  • 90rust-code-expert
    Pomaga przy rozwiązaniach w Rust, gdy o wyniku decydują własność, czasy życia, traity, async/Tokio, unsafe, FFI lub Cargo.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.