ffi.types
import ffi.types
ffilifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledffi.types.*needsimport ffi.types.
C types as values.
Every type the module works with is a Type: the built-in ones the
module exports (ffi.int, ffi.double, ffi.size_t), the ones built
from them (ffi.pointer(ffi.char), ffi.array(ffi.int, 4)), records
built member by member, and every type a declaration names. A type knows
its size and alignment on this platform, and it is what every conversion
between a Zuri value and C memory is driven by.
Records are built with chained calls and are laid out the first time anything needs their size, after which they can no longer change:
var Point = ffi.struct('Point')
.add_field('x', ffi.double)
.add_field('y', ffi.double)
echo Point.size()
Classes
Type
class ffi.Type
A C type.
Types are never constructed directly. They come from the module’s constants and builders, and from declarations.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
ffi.Type()
Type.name()
ffi.Type.name() -> string
The type as C spells it: int, const char *, struct point, or the
name a typedef or a Rust declaration gave it.
Returns string
Type.kind()
ffi.Type.kind() -> string
What sort of type this is.
One of 'void', 'bool', 'int' (every integer and character type),
'float' (float, double and long double), 'complex', 'char'
(a Rust char), 'pointer', 'string' (a pointer that converts to and
from a string), 'function pointer', 'array', 'struct', 'union',
'enum' (C enums and Rust enums alike) and 'function'.
Returns string
Type.size()
ffi.Type.size() -> number
Size in bytes on this platform, as C’s sizeof gives it.
Asking for a record’s size lays the record out, after which no member can be added to it.
Returns number
Raises FfiError when the type has no size: void, a function, an
array without a length, or a record that was declared and never defined.
Type.align()
ffi.Type.align() -> number
Alignment in bytes on this platform, as C’s _Alignof gives it.
Returns number
Raises FfiError when the type has no alignment, for the same types
that have no size.
Type.is_const()
ffi.Type.is_const() -> bool
Whether the type is const-qualified.
A pointer to a const type is never written through, so a list or
dictionary passed for one is not updated after the call.
Returns bool
Type.target()
ffi.Type.target() -> Type|nil
The type this one is made from: what a pointer points at, what an array
holds, or the integer type an enum is stored as. nil for every other
type.
Returns Type|nil
Type.length()
ffi.Type.length() -> number|nil
An array type’s number of elements, or nil for any other type and for
an array declared without a length.
Returns number|nil
Type.signature()
ffi.Type.signature() -> dict|nil
The signature of a function type or a function pointer type, as { returns, params, variadic, abi },
or nil for any other type.
returns is a Type, params a list of them, variadic whether
arguments may follow the fixed ones, and abi the calling convention’s
name: 'default', 'win64' or 'sysv64'.
Returns dict|nil
Type.pointer()
ffi.Type.pointer() -> Type
A pointer to this type; the same as ffi.pointer(type).
Returns Type
Type.array()
ffi.Type.array(length) -> Type
An array of length values of this type; the same as ffi.array(type, length).
Parameters
length(number|nil) — Leave out for an array of unknown length, as a flexible array member is declared.
Returns Type
Type.as_const()
ffi.Type.as_const() -> Type
This type with const added.
Returns Type
Type.of()
ffi.Type.of(value) -> Typed
value marked as this type, for passing to a variadic function.
A variadic function’s extra arguments have no declared types, so each
one otherwise travels as the type its value suggests (see
Library.function()). This fixes it instead:
c.printf('%f %ld\n', ffi.double.of(1), ffi.long.of(7))
C’s default promotions still apply on top: a float travels as a
double, and an integer narrower than int as an int.
Parameters
value(any)
Returns Typed
Type.equals()
ffi.Type.equals(other) -> bool
Whether other is the same type.
Scalars, pointers and arrays compare by shape, so ffi.int32 equals
ffi.int, and a typedef equals what it names. Records and enums compare
by identity: two structs built separately are different types even with
the same members, as they are in C.
Parameters
other(any)
Returns bool
Type.to_string()
ffi.Type.to_string()
RecordType
class ffi.RecordType < Type
A struct or a union, built member by member.
Members go in declaration order, each at the offset the platform’s C compiler would give it: GCC and Clang’s rules on Linux and macOS, MSVC’s on Windows. The two differ only for bitfields. The record is laid out the first time anything needs its size, including passing a value of it, and from then on it cannot change.
- printable — has a
@to_string(), soechoandprint()show something useful
RecordType.add_field()
ffi.RecordType.add_field(name: string, type, align)
Adds a member, returning the record for chaining.
var Header = ffi.struct('Header')
.add_field('magic', ffi.uint32)
.add_field('payload', ffi.uint8.array(16))
.add_field('checksum', ffi.uint64, 16)
An array type without a length is a flexible array member and must come last. A struct or union added with an empty name is an anonymous member, whose own members are reached as this record’s.
Parameters
name(string)type(Type)align(number|nil) — A minimum alignment in bytes, as_Alignasgives a member. A power of two. Defaults to the type’s own.
Returns — self
Raises FfiError when the record has already been laid out, the
name is taken, or a member follows a flexible array member.
RecordType.add_bitfield()
ffi.RecordType.add_bitfield(name: string, type, bits: number)
Adds a bitfield, returning the record for chaining.
var Flags = ffi.struct('Flags')
.add_bitfield('ready', ffi.uint, 1)
.add_bitfield('mode', ffi.uint, 3)
.add_bitfield('', ffi.uint, 0)
.add_bitfield('count', ffi.uint, 12)
An empty name is an unnamed bitfield, which only takes up space; one of width zero ends the current storage unit, as in C.
Parameters
name(string)type(Type) — An integer,boolor enum type.bits(number) — The width, at most the type’s own.
Returns — self
Raises FfiError when the type is not an integer type or the width
does not fit it.
RecordType.set_packed()
ffi.RecordType.set_packed(bytes)
Packs the members to at most bytes alignment, as #pragma pack(n)
does, or tightly when bytes is left out, as __attribute__((packed))
does.
Parameters
bytes(number|nil) — 1, 2, 4, 8 or 16. Defaults to 1.
Returns — self
RecordType.set_align()
ffi.RecordType.set_align(bytes: number)
Raises the record’s own alignment to at least bytes, as
__attribute__((aligned(n))) on the record does. Its size grows to a
multiple of the new alignment.
Parameters
bytes(number) — A power of two.
Returns — self
RecordType.fields()
ffi.RecordType.fields() -> list
Every member in declaration order, with the members of anonymous members listed in their place.
Each is { name, type, offset, bits, bit_offset }. offset is in bytes
from the start of the record. For a bitfield, bits is its width and
bit_offset the position of its first bit from the start of the record;
both are nil for every other member.
Returns list
RecordType.offset_of()
ffi.RecordType.offset_of(name: string) -> number
A member’s offset in bytes, as C’s offsetof gives it. For a bitfield,
the byte its first bit is in.
Parameters
name(string)
Returns number
Raises ValueError when there is no such member.
RecordType.has_field()
ffi.RecordType.has_field(name: string) -> bool
Whether the record has a member called name.
Parameters
name(string)
Returns bool
RecordType.variants()
ffi.RecordType.variants() -> dict|nil
For a Rust enum with fields, each variant’s name and discriminant; nil
for an ordinary record.
Returns dict|nil
StructType
class ffi.StructType < RecordType
A C struct, or a Rust #[repr(C)] struct or enum with fields.
A struct value passes into C as a dictionary of its members and comes
back out as one. A member left out of the dictionary is zero. A Rust
enum with fields is a dictionary too, with a variant key naming the
variant, and a variant without fields may be passed as just its name.
- printable — has a
@to_string(), soechoandprint()show something useful
UnionType
class ffi.UnionType < RecordType
A C union.
A union value passes into C as a dictionary holding exactly one of its members, the one to store. Read back, it is a dictionary of every member, each read from the same bytes, since which one is meaningful is something only the program knows.
- printable — has a
@to_string(), soechoandprint()show something useful
EnumType
class ffi.EnumType < Type
A C enum, or a Rust enum without fields.
A value of an enum type is a number, and anywhere one is passed in, the name of a constant can be passed instead:
var Color = ffi.enum('Color').add_constant('RED', 0).add_constant('GREEN', 1)
set_color('GREEN')
- printable — has a
@to_string(), soechoandprint()show something useful
EnumType.add_constant()
ffi.EnumType.add_constant(name: string, value)
Adds a named constant, returning the enum for chaining.
Parameters
name(string)value(number) — An integer that fits the enum’s storage type.
Returns — self
Raises ValueError when the enum already has a constant of that
name.
Raises RangeError when the value does not fit.
EnumType.constants()
ffi.EnumType.constants() -> dict
Every constant, by name, in the order they were declared.
Returns dict
EnumType.value()
ffi.EnumType.value(name: string) -> number
The value of the constant called name.
Parameters
name(string)
Returns number
Raises ValueError when there is no such constant.
Typed
class ffi.Typed
A value marked with the C type it should travel as. Made by Type.of(),
and only meaningful as an argument to a variadic function.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
ffi.Typed(type, value)
Parameters
type(Type)value(any)
Typed.type()
ffi.Typed.type() -> Type
The type the value travels as.
Returns Type
Typed.value()
ffi.Typed.value() -> any
The value itself.
Returns any
Typed.to_string()
ffi.Typed.to_string()
2026, Richard Ore and Zuri contributors