[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 18/25] write documentation for (system foreign declarative)

From: KAction
Subject: [PATCH 18/25] write documentation for (system foreign declarative)
Date: Mon, 18 Jul 2016 18:17:41 +0300

From: Dmitry Bogatov <address@hidden>

Document '<foreign-type>' record type and 'define-foreign-type' procedure.
 doc/ref/api-foreign.texi | 150 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 147 insertions(+), 3 deletions(-)

diff --git a/doc/ref/api-foreign.texi b/doc/ref/api-foreign.texi
index c2c49ec..605dbed 100644
--- a/doc/ref/api-foreign.texi
+++ b/doc/ref/api-foreign.texi
@@ -26,6 +26,7 @@ procedures.
 * Modules and Extensions::      Loading C extensions into modules.
 * Foreign Pointers::            Accessing global variables.
 * Dynamic FFI::                 Calling arbitrary C functions.
+* Declarative dynamic FFI::     Declarative macros for calling C functions
 @end menu
@@ -439,10 +440,10 @@ section takes up the problem of accessing C values from 
Scheme, and the
 next discusses C functions.
-* Foreign Types::                  Expressing C types in Scheme.
-* Foreign Variables::              Pointers to C symbols.
+* Foreign Types::               Expressing C types in Scheme.
+* Foreign Variables::           Pointers to C symbols.
 * Void Pointers and Byte Access::  Pointers into the ether.
-* Foreign Structs::                Packing and unpacking structs.
+* Foreign Structs::             Packing and unpacking structs.
 @end menu
 @node Foreign Types
@@ -980,6 +981,149 @@ on a few exotic architectures.  Thus, user code may need 
to check
 many architectures, including (as of libffi 3.0.9) x86, ia64, SPARC,
 PowerPC, ARM, and MIPS, to name a few.
address@hidden Declarative dynamic FFI
address@hidden Declarative dynamic FFI
+Dynamic foreign function interface, described in previous section is
+powerful and sufficient to bind power of almost any C library to Guile
+with only Scheme code. But it is very low-level and does not provide any
+abstractions for common function conventions. This is where module
address@hidden(system foreign declarative)} comes into the game.
address@hidden {Record type} <foreign-type> name validate encode decode type
address@hidden<foreign-type>} record represents correspondence between C data
+type and some Scheme object. It contains @code{name} for purposes of
+error reporting, procedure @code{validate}, which will can be called
+with single argument and return @code{#t} if it's argument is suitable
+for passing to @code{encode} procedure, and return @code{#f} or throw if
+Procedure @code{encode} converts Scheme object of arbitrary complexity
+to C data type, coherent to @code{type}. @xref{Dynamic FFI} Procedure
address@hidden converts back from C data type to some Scheme object.
+At least one of them should be present for record be useful.
+Fields of @code{<foreign-type>} record must (but not enforced)
+to obey following rules:
+Every procedure @code{validate}, @code{encode} and @code{decode} are
+pure -- their result depends only on argument, and they do nothing,
+except of returning a value.
+;; for every `procedure' from 'validate', 'encode', 'decode'
+;; for every Scheme value `x'
+;; following expressions are either both throw or return same value.
+;; they can freely be replaced one with another.
+(list (procedure x)
+      (procedure x))
+(let ((value (validate x))
+     (list value value)))
address@hidden example
+If field @code{decode} is present, procedure @code{decode} accepts any
+argument with type matching @code{type} field and returns normally some
+value. If both @code{decode} and @code{encode} fields are present,
+value, returned by @code{decode} procedure, can be encoded back by
address@hidden procedure.
+;; For every Scheme value 'x', matching field 'type' following expression
+;; never throw and always evaluates to #t
+(equal? (encode (decode x)) x)
address@hidden example
+For every value, for which @code{validate} procedure returned @code{#t},
address@hidden procedure returns normally.
+;; For every Scheme value 'x' following expression never throws
+(and (false-if-exception (validate x))
+     (encode x))
address@hidden example
address@hidden enumerate
address@hidden deftp
address@hidden {Scheme Macro} define-foreign-type name  @
+        [#:validate-proc=(const #t)]            @
+        [#:encode-proc=error]                   @
+        [#:decode-proc=error]                   @
+        [#:type='*]
+Defines @code{name} to a @code{<foreign-type>} record with @code{name},
+fields @code{validate-proc}, @code{encode-proc}, @code{decode-proc},
address@hidden configured with keywords arguments.
+Here is how one may define foreign type record, that match C integer with
+Scheme boolean
+(use-modules (system foreign)) ;; `int' is defined there
+(use-modules (system foreign declarative))
+(define (boolean->integer b)
+  (if b 1 0))
+(define (integer->boolean i)
+  (not (zero? i))
+(define-foreign-type boolean:
+  #:validate-proc boolean?
+  #:encode-proc boolean->integer
+  #:decode-proc integer->boolean
+  #:type int)
address@hidden example
+By convention, @code{<foreign-type>} record's names ends with colon.
address@hidden deffn
+Module @code{(system foreign declarative)} provides such records for
+every primitive C type exported by @code{(system foreign)}.
address@hidden {Scheme Macro} define-foreign-function function-name ((type 
name) ...) :: return @
+       [#:dynamic-library=(dynamic-link)] [#:symbol]
+Define Scheme procedure @code{function-name}, that wraps C function with name 
+from dynamic library @code{dynamic-library}. Both @code{return} and 
@code{type} arguments
+must be @code{<foreign-type>} records, to specify how to pass arguments to 
+C function.
+Arguments, passed to @code{function-name} are validated and encoded
+according to specified @code{type}s, passed to C function. Return value
+of C function is decoded according to @code{return} foreign-type record.
address@hidden is name of C function, unless specified explicitly is deduced
+from @code{function-name} by following rules:
+Remove prefix "c-" prefix, if present.
+Replace every non-alphanumeric symbol with underscores.
address@hidden enumerate
+Here are some examples of @code{define-foreign-function} usage:
+;; In such simple case neither 'dynamic-library' keyword needed, since
+;; 'sin' function is already in library, pulled by libguile, neither
+;; 'symbol' keyword, since underlying function name "sin" is deduced
+(define-foreign-function c-sin ((double: arg)) :: double:)
+(equal? (c-sin 10) (sin 10)) ; #t
+;; In case of time(3) function, we must specify correct signature,
+;; but we can %null-pointer and hide implementation details.
+(define ask-time
+  (let ()
+    (define-foreign-function c-time ((*: t)) :: long:)
+    (lambda ()
+      (c-time %null-pointer))))
+(ask-time) ; 1468434734, at time of writing
+;; We can as easily work with constant strings
+(define-foreign-time c-rename ((string: oldpath) (string: newpath)) :: int:)
address@hidden example
address@hidden deffn
 @c Local Variables:
 @c TeX-master: "guile.texi"
 @c End:
I may be not subscribed. Please, keep me in carbon copy.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]