(defpackage #:s11-cffi (:use #:common-lisp #:cffi)) ;; private CFFI symbols I need (eval-when (:compile-toplevel :load-toplevel :execute) (import '(cffi::foreign-typedef cffi::define-type-spec-parser cffi::parse-type cffi::unparse cffi::unparse-type cffi::expand-type-to-foreign-dyn))) ;; I also use cffi::name, but decided leaving that fully qualified ;; would reduce confusion. (in-package #:s11-cffi) (defclass foreign-in-out-argument (foreign-typedef) ((pointee-type :initarg :pointee-type :reader pointee-type)) (:documentation "TODO")) (define-type-spec-parser in-out (pointee-type) (make-instance 'foreign-in-out-argument :name 'in-out :actual-type (parse-type ':pointer) :pointee-type (parse-type pointee-type))) (defmethod unparse (name (type foreign-in-out-argument)) (list name (unparse-type (pointee-type type)))) (defvar .in-out-sink.) (setf (documentation '.in-out-sink. 'variable) "List of in-out output arguments collected by call-with-in-out-arguments.") (defmethod expand-type-to-foreign-dyn (value-form var-form body (type foreign-in-out-argument)) (let ((pointee-type (list 'quote (unparse-type (pointee-type type))))) `(with-foreign-object (,var-form ,pointee-type) (setf (mem-ref ,var-form ,pointee-type) ,value-form) ,@body (push (mem-ref ,var-form ,pointee-type) .in-out-sink.)))) (defun call-with-in-out-arguments (thunk) "Call thunk, collecting any in-out arguments in foreign functions called therein, appending them in order to the primary result." (let ((.in-out-sink. '())) (multiple-value-call #'values (values (funcall thunk)) (values-list .in-out-sink.))))