Data Model

In addition to the macros and functions provided to build a Clojure API for native libraries, facilities are provided for taking data and loading all the symbols specified by it. This can be useful if a library provides (or an external provider maintains) a data representation of their API, as Clojure data to represent it may be programmatically generated from these sources.

The data to represent an API is a map with the following form:

(def strlen-libspec
  {:strlen {:type :function
            :symbol "strlen"
            :function/args [::mem/c-string]
            :function/ret ::mem/long}})

Each key in this map represents a single symbol to be loaded. The value is a map with at least the keys :type and :symbol. These are the currently recognized types:

  • function
  • varargs-factory
  • const
  • static-var

Each one has its own set of additional keys which can be added to the map. Both function and varargs-factory have the three keys :function/args, :function/ret, and :function/raw-fn?. The const type has :const/type and static-var has :static-var/type.

This data can be passed to the function reify-libspec, which will take the data and return a map from the same keys as the input map to whatever value is appropriate for a given symbol type (e.g. a Clojure function for function, a value for const, etc.).

(ffi/reify-libspec strlen-libspec)
;; => {:strlen #function[...]}

This functionality can be extended by specifying new types as implementations of the multimethod reify-symbolspec, although it’s recommended that for any library authors who do so, namespaced keywords be used to name types.