hbabcockos1@mac.com writes:
(pl-defcfun ("c_plmesh" plmesh) :void (x *plflt nx) (y *plflt ny) (z **plflt (nx ny)) (nx plint) (ny plint) (opt plint))
This is interesting and I think this is doable using plain defcfun and CFFI's type system. If it's not, it should.
(in-package #:cffi)
(defclass my-array (foreign-type-alias) ((dimensions :initarg :dimensions :reader dimensions)))
(define-type-spec-parser my-array (type &rest dimensions) (make-instance 'my-array :actual-type (parse-type type) :dimensions dimensions))
(defmethod expand-type-to-foreign-dyn (value var body (self my-array)) `(let ((,var (generate-array (list ,@(dimensions self)) ,value))) (unwind-protect (progn ,@body) (free-array ,var))))
(defcfun "plmesh" :void (x (my-array :float nx)) ; tk me a whl to fgr that plflt (y (my-array :float ny)) ; probably means float, heh (z (my-array :float nx ny)) (nx :int) (ny :int) (opt :int))
The macro expansion of the DEFCFUN above looks something like this:
(DEFUN PLMESH (X Y Z NX NY OPT) (LET ((#:G1046 (GENERATE-ARRAY (LIST NX) X))) (UNWIND-PROTECT (PROGN (LET ((#:G1047 (GENERATE-ARRAY (LIST NY) Y))) (UNWIND-PROTECT (PROGN (LET ((#:G1048 (GENERATE-ARRAY (LIST NX NY) Z))) (UNWIND-PROTECT (PROGN (LET ((#:G1049 NX)) (LET ((#:G1050 NY)) (LET ((#:G1051 OPT)) (VALUES (%FOREIGN-FUNCALL "plmesh" :POINTER #:G1046 :POINTER #:G1047 :POINTER #:G1048 :INT #:G1049 :INT #:G1050 :INT #:G1051 :VOID)))))) (FREE-ARRAY #:G1048)))) (FREE-ARRAY #:G1047)))) (FREE-ARRAY #:G1046))))
So, again, your example is quite interesting because it reminds me that we should export all of the functionality of the type system. In particular, the ability to get at type arguments in the type translators seems quite useful.
(Also, Greg Pfeil has been running into the "limitation" that typedefs don't behave like other user-defined types, such as structs and enums, with regard to type translators.)
I've been thinking about how to nicely export this kind of functionality to the user and this is what I came up with:
;;; thin wrapper around defclass with cffi::foreign-type as a super (define-foreign-type foo () (slot1 slot2) (:documentation "foo"))
(defmethod parse-type ((name (eql 'foo)) args) (destructuring-bind (bar &key baz) args (make-instance 'foo ...)))
Possibly with some syntactic sugar over that defmethod:
(define-parse-method foo (bar &key baz) (make-instance 'foo ...))
And the default method could be something like this:
(defmethod parse-type (name args) (apply #'make-instance name args))
Then we need to think about how typedefs would fit into this more CLOS-based type interface. Hopefully, we'd unify the translate/expand-[type-|]to/from-foreign{-dyn} pairs (ie. those with "type" in the name and those without).
Last but not the least, your example reminds me that we need to add an array type and to finish the shareable vectors interface, etc...
So, thanks! :-)