Skip to content
heff

ffi

C’s types as values, and an effect’s operations that C functions do: a description, which the compiler reads where it compiles the program for C, and makes the provider’s side of — how an operation’s fields are given to the function, what its result is made into, and the dispatch — in place of the same written by hand in the module’s M.provider.c. The C compiler is given, with the glue, the types described, held to the function’s own as its header declares it: a function described as taking an int where it takes a size_t does not build.

This is how a module gives the program the host’s types — what a FILE * is to it, with what lets it go — and nothing more: an operation stays an effect’s, done when a handler handles it; the program itself never calls C. A function of no effect (libm’s sin, a hash) is a primitive of the runtime’s or the library’s, not described here: C cannot be trusted to say it is pure.

A description is a definition of type Described in the effect’s module (std.time’s timeInC), of the operations C does: each a constructor’s name, and the function, with its C type as values of CType, as Racket’s ffi has them. An operation Op a b (r -> x) described fun "f" [ta, tb] (Gives tr) is f(a, b), its result made an r as tr says; one whose last field is x itself gives void. What the module’s M.provider.c does by hand is still its own: its heff_provider_M hands an operation it does not do to heff_described_M, the glue; a module all of whose operations are described needs no M.provider.c. In JavaScript a description means nothing: the module’s M.provider.js is the whole of the effect there.

CType

data CType
= CInteger String
| CDouble
| CBool
| CString
| CText
| COwnedString
| CBytes
| COwnedBytes
| CPointer String String
| CVoid

A C type, by what crosses as it:

  • CInteger "int", an integer type by its C name (int, int64_t, size_t, mode_t: a typedef’s name, so that its width is the system’s, not guessed), of an Int;
  • CDouble, a Float64; CBool, a Bool (C’s bool);
  • CString, const char *: a String’s bytes, a NUL after them (a path, content); CText, the same made valid UTF-8 (a name); COwnedString, a result only: a char * malloc’d by C, copied and freed;
  • CBytes, a Bytes, NULs and all: as an argument two of C’s, its bytes’ const unsigned char * and their count, a size_t; as a result const unsigned char *, the count put by the function in a size_t * given after its arguments, the bytes copied; COwnedBytes, a result only: the same, unsigned char * malloc’d by C, copied and freed;
  • CPointer "FILE" "fclose", a pointer to the named type (FILE *), held by the program as a foreign value of whatever type the operation says (a data of no constructors), and let go of by the named function when the program drops its last reference;
  • CVoid, a result only: Unit.

CResult

data CResult = Gives CType | GivesOrErrno CType | DoneOrErrno

What a function’s result is made into:

  • Gives t, the result as the operation’s answer (of CVoid, the operation’s x itself, or MkUnit to its function); NULL of a string, bytes or a pointer fails the program (no bytes are given as a pointer still, their count 0);
  • GivesOrErrno t, Either Errno a: the system’s way of failing, -1 of an integer or NULL of a string, bytes or a pointer with errno set, Left of it, else Right the result;
  • DoneOrErrno, Either Errno Unit: an int, 0 or -1 with errno.

Errno

type Errno = { code : Int, name : String, message : String }

Why a call of the system failed: errno, its name (ENOENT, EACCES; the same on every system, where the number is not), and what the system says of it. (std.filesystem’s FileError is one, and the path it was of.)

Function

type Function = { name : String, args : List CType, result : CResult }

A C function: its name, as the header the module includes declares it (or as the module’s M.provider.c defines it), what it takes, and what it gives.

Operation

type Operation = { op : String, fun : Function }

An operation done by a C function: the constructor’s name, and the function, which is given the operation’s fields but its last, in order.

Described

data Described = Describe (List String) (List Operation)

An effect’s operations in C: the headers the functions are declared in ("<stdio.h>", as written after #include; none for a function of M.provider.c), and the operations.

type Links =
{ pkgConfig : List String = []
, libs : List String = []
, frameworks : List String = []
}

What a module’s C needs beyond the runtime to be built and linked, said by a definition of this type in the module, so that every program importing it is built so:

  • pkgConfig, packages by their pkg-config names, whose pkg-config --cflags and --libs are given to the C compiler;
  • libs, libraries by their names, each -lNAME;
  • frameworks, macOS frameworks by their names, each -framework NAME, where the program is built for macOS (nowhere else, where a provider does without them).

Where a library is found, if neither pkg-config nor the C compiler knows, is the program’s build to say (its includeDirs and libDirs), not the module’s.

int

int : CType

int.

int64

int64 : CType

int64_t.

long

long : CType

long.

size

size : CType

size_t.

integer

integer : String -> CType

An integer type by its C name: integer "mode_t".

double

double : CType

double.

bool

bool : CType

bool.

string

string : CType

const char *, a string’s bytes.

text

text : CType

const char *, text.

ownedString

ownedString : CType

char * malloc’d by C, a result.

bytes

bytes : CType

A Bytes: const unsigned char * and size_t, an argument; as a result, the count by a size_t * after the arguments.

ownedBytes

ownedBytes : CType

unsigned char * malloc’d by C, its count by a size_t * after the arguments, a result.

pointer

pointer : String -> String -> CType

A pointer to the named type, let go of by the named function: pointer "FILE" "fclose".

void

void : CType

void, a result.

gives

gives : CType -> CResult

The result as the answer.

givesOrErrno

givesOrErrno : CType -> CResult

The result, or Left errno where it is -1 or NULL.

doneOrErrno

doneOrErrno : CResult

Right MkUnit of 0, Left errno otherwise.

fun

fun : String -> List CType -> CResult -> Function

A C function described.

>>> (fun "chmod" [string, integer "mode_t"] doneOrErrno).name
"chmod"

operation

operation : String -> Function -> Operation

An operation done by a function.

>>> (operation "Sleep" (fun "heff_sleep_ms" [int64] (gives void))).op
"Sleep"

describe

describe : List String -> List Operation -> Described

The operations C does, with the headers their functions are declared in.

instanceShowErrno

instance instanceShowErrno : Show Errno

As a system’s tools say it: the name, and what it is.

>>> show ({ code = 2, name = "ENOENT", message = "No such file or directory" } : Errno)
"ENOENT: No such file or directory"