bridge

Bridge between FatScript and external C libraries

The bridge library allows FatScript to interface with external C libraries by providing dynamic linking capabilities and foreign function interface (FFI) bindings. This is useful for leveraging performance advantages of C and using existing C libraries in FatScript applications.

Import

_ <- fat.bridge

Types

The bridge library introduces two primary types for handling dynamic linking of external libraries and calling foreign functions: DLL and FFI.

DLL

The DLL type represents a handle to a dynamically loaded library.

Constructor

Name Signature Brief
DLL (filename) Loads a dynamic library

The DLL constructor takes the following argument:

  • filename: The path to the shared object (.so/.dll) file to be loaded.

FFI

The FFI type allows binding to external functions from the dynamically loaded library, using FatScript's CType system to match the function's expected input and output types.

Constructor

Name Signature Brief
FFI (lib, name, in, out) Binds to an external function

The FFI constructor takes the following arguments:

  • lib: A DLL instance representing the loaded library.
  • name: A name (Text) of the function to bind within the library.
  • in: A List/Ctype of argument types expected by the function.
  • out: The CType return type of the function.

Prototype members

Name Signature Brief
call (args...): Any Calls the bound function

Aliases

  • CPointer: Represents a memory pointer (void*-like), base type is Chunk.
  • CType: Represents C data types in FatScript, base type is Number.

CType

The CType system maps common C types to corresponding FatScript types, allowing safe interaction with C libraries.The following types are made available in the ctype scope and implement automatic correspondence with FatScript types:

Name C type Correspondence
sint int Number
sintP int* Number
uint unsigned int Number
uintP unsigned int* Number
float float Number
floatP float* Number
double double Number
doubleP double* Number
schar char Chunk
scharP char* Chunk
uchar unsigned char Chunk
ucharP unsigned char* Chunk
sshort short Number
sshortP short* Number
ushort unsigned short Number
ushortP unsigned short* Number
slong long Number
slongP long* Number
ulong unsigned long Number
ulongP unsigned long* Number
string char* (return type) Text
void void (return type) Void
voidP void* Chunk

string must be a dynamically allocated, null-terminated char pointer.

Standalone methods

Name Signature Brief
unsafePeek (ptr: CPointer, offset: Number, len: Number): Chunk Reads from ptr considering offset and length
detachNode (node: Any): Void Releases ownership of memory
marshal (val: Any, type: CType): Chunk Marshals a FatScript value to a raw C type
unmarshal (raw: Chunk, type: CType): Any Unmarshals from a C type back to FatScript
getErrno (): Number Returns the errno from the last FFI call
sizeOf (type: CType): Number Gets the number of bytes for a given CType

unsafePeek

Allows direct reading of raw memory, which can be used to interface with C data structures. Warning: This method performs no bounds checking and relies on correct parameters. Misuse can cause system crashes or security vulnerabilities.

detachNode

Relinquishes ownership of memory pointed to by Text or Chunk to prevent double freeing of memory. Consult external library documentation to understand memory ownership before using detachNode, as it's not always necessary.

marshal

Converts a FatScript value to a raw memory chunk using a specific CType. Useful for composing C structs. Only string and voidP are valid for marshaling Text and Chunk as pointers types respectively. Warning: Ensure proper handling of buffer pointers to avoid double freeing of memory.

unmarshal

Casts raw memory chunks to specific FatScript types based on CType. Useful for interpreting data returned from C structs. Warning: Incorrect usage or incorrect CType can result in undefined behavior or data corruption.

getErrno

The errno from the last FFI call is cached and can be retrieved through this method.

sizeOf

Determines the memory size (in bytes) of a given CType. This is can be useful for safely using functions like unsafePeek.

Example Usage

Loading a library

To load a dynamic library, use the DLL type:

zlibDLL = DLL('libz.so')

This will attempt to load the libz.so shared object library (in this example, the zlib compression library).

Binding to a function

To bind to a function within the loaded library, use the FFI type:

compressFFI = FFI(zlibDLL, 'compress', [ucharP, slongP, ucharP, slong], sint)

This binds to the compress function in the zlib library. The argument types and return type are specified using CType.

Calling the function

Once bound, you can call the function using the call method:

compressedData = compressFFI.call(destBuff, destSize, source, sourceSize)

This calls the compress function and returns the result.

Full Example: compressing data with zlib

_      <- fat.type._
bridge <- fat.bridge

zlibDLL = DLL('libz.so')

{ ucharP, slong, slongP, sint } = bridge.ctype

compressFFI = FFI(zlibDLL, 'compress', [ucharP, slongP, ucharP, slong], sint)

# Compress data
source = 'Hello, zlib compression!'.toChunk
destSize = 256
destBuff = Chunk(256)

compressedData = compressFFI.call(destBuff, destSize, source, source.size)

Note that destSize uses the slongP type mapping, and while it is considered immutable in FatScript, it may be mutated through the function call. This is expected behavior and is way of interfacing FatScript with C.

Advanced raw data manipulation

To have a better understanding of how bridge works, you can study the FFI test case and the sample implementation projects zlib.fat and qrcode.fat.

Bridge in Web Build

When using fry built with Emscripten (for example, when using FatScript Playground), there is no support for this library.

results matching ""

    No results matching ""