std::ffi::c (C FFI helpers)
This module provides small, explicit helpers for interoperating with C APIs
from Silk via ext declarations.
The initial focus is C strings (char* / const char*): pointers to
NUL-terminated bytes. In Silk, these pointers are represented as raw addresses
(u64).
Canonical C scalar aliases#
Silk int is not C int (int is a 64-bit scalar in the current ABI; see
ext). For conventional C APIs, prefer std::ffi::c scalar
aliases in your ext signatures:
c_int/c_uintc_long/c_ulongsize_t/ssize_tintptr_t/uintptr_t/ptrdiff_t
These are POSIX-first mappings intended to match the common C ABI widths on our hosted targets.
C string helpers#
Borrowed vs owned#
cstr_borrow/cstr_stringproduces a borrowed Silkstringview into the original C memory. It does not allocate.cstr_copyproduces an ownedstd::strings::Stringcopy (heap allocation, NUL-terminated).std::ffi::c_owned::OwnedCStrrepresents an owned C string pointer (char*) paired with a user-provided release function and drops it deterministically.
Use cstr_copy when the C pointer is only valid temporarily (for example, when
it is owned by a C library object that may be freed, or when the pointer is
documented to be invalidated by the next API call).
Null pointers#
C APIs frequently use NULL as “no string”.
cstr_string(ptr)treatsptr == 0as"".cstr_string_opt(ptr)returnsNonewhenptr == 0.
Choose the form that matches the C API contract you are binding.
Safety notes#
cstr_lenscans memory until it finds a0byte. If the pointer is invalid or not NUL-terminated, behavior is undefined.- These helpers do not validate UTF-8. A C string may contain arbitrary bytes.
Exported API#
- C scalar aliases:
c_int,size_t,ssize_t, … cstr_len(ptr: u64) -> intcstr_borrow(ptr: u64) -> stringcstr_string(ptr: u64) -> string(alias ofcstr_borrow)cstr_borrow_opt(ptr: u64) -> string?cstr_string_opt(ptr: u64) -> string?(alias ofcstr_borrow_opt)cstr_copy(ptr: u64) -> Result(std::strings::String, std::memory::OutOfMemory)
Owned pointers (std::ffi::c_owned)#
CFreeFn = fn (u64) -> voidcstr_copy_and_free(ptr: u64, free_fn: CFreeFn) -> Result(std::strings::String, std::memory::OutOfMemory)OwnedCStr(owned pointer + drop)Dropreleases the underlying C allocation and nulls the pointer.Lenreturns the current C string length in bytes.IsEmptyreports whether the pointer is null or points at an empty string.Serialize(string)returns the borrowed Silkstringview, soowned as stringis the canonical cast path.TrySerialize(std::memory::OutOfMemory)returns an ownedstd::strings::Stringcopy for callers that need the bytes to outlive the underlying C allocation.
Notes:
OwnedCStr.len()scans until the terminating NUL each time, just likecstr_len.OwnedCStr.serialize()andOwnedCStr.as_string()borrow the C bytes; if you need an owned Silk allocation, callOwnedCStr.try_serialize()orOwnedCStr.copy()instead.
Example#
import c_owned from "std/ffi/c_owned";
import std::runtime::mem;
fn main () -> int {
let p: u64 = std::runtime::mem::alloc(3);
if p == 0 { return 1; }
std::runtime::mem::store_u8(p, 0, 104);
std::runtime::mem::store_u8(p, 1, 105);
std::runtime::mem::store_u8(p, 2, 0);
let free_fn: c_owned::CFreeFn = fn (ptr: u64) {
std::runtime::mem::free(ptr);
};
let mut owned = c_owned::OwnedCStr.from_ptr(p, free_fn);
let v: string = owned as string;
if v != "hi" { owned.drop(); return 2; }
if owned.len() != 2 { owned.drop(); return 3; }
if owned.is_empty() { owned.drop(); return 4; }
owned.drop();
return 0;
}
Source repository · Edit this page · View Markdown