FFI & External Interface
Use extern declarations to call external symbols such as C library functions or system APIs. When using FFI, make sure your parameter types, memory layout, and resource cleanup match the external API.
Extern Blocks
Section titled “Extern Blocks”extern { public Int puts(UInt8* text); public Int open(UInt8* path, Int options); public Int errno;}Single declarations can use top-level modifiers:
extern public Int puts(UInt8* text);public extern Int errno;C Strings
Section titled “C Strings”C APIs represent strings as UInt8*. A string literal passed in that context is emitted as
null-terminated read-only data:
extern public Int puts(UInt8* text);
puts("hello from Jiang");Borrowed sentinel string views use UInt8[:0]&. Use $.ptr() when a C API needs a raw pointer.
Use view.slice() or view$.as(UInt8[]&) when Jiang code needs to treat a
non-literal sentinel view as a plain byte slice:
UInt8[:0]& view = "hello";unsafe { puts(view$.ptr());}
UInt8[]& bytes = view.slice();When a C API needs a pointer plus a length, model the pointer and length explicitly:
extern public Int write(Int fd, UInt8* buf, Int count);Raw Pointers
Section titled “Raw Pointers”T* is a raw pointer for FFI, ABI, and low-level code:
Int value = 42;Int* raw = unsafe { value$.ptr()};Int copied = raw$.get();Writing through a single-object raw pointer requires a mutable pointee:
Int value! = 0;Int*! raw = unsafe { value$.mut_ptr()};raw$.set(42);Raw Buffer Pointers
Section titled “Raw Buffer Pointers”T* is also the unbounded raw contiguous-memory view used by C buffer parameters:
extern Int read(Int fd, UInt8*! buf, Int count);Indexing raw pointers is unsafe because they carry no length. T* can be indexed for reads, while
T*! also permits writes. Wrap the pointer with a length field or use T[]& when Jiang code needs a
borrowed length-bearing view. T[*] and T[*:S] have been removed.
Resource Boundaries
Section titled “Resource Boundaries”When wrapping external resources, make ownership explicit:
struct CBuffer { UInt8*! data; Int length;
deinit(self) { unsafe { self.data$.dealloc(); } return (); }}