libffi: clean up the ABI enum
[cffi.git] / src / types.lisp
blob83e851c826579dcf20e876f4383d01392ae7dd4f
1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
2 ;;;
3 ;;; types.lisp --- User-defined CFFI types.
4 ;;;
5 ;;; Copyright (C) 2005-2006, James Bielman <jamesjb@jamesjb.com>
6 ;;; Copyright (C) 2005-2007, Luis Oliveira <loliveira@common-lisp.net>
7 ;;;
8 ;;; Permission is hereby granted, free of charge, to any person
9 ;;; obtaining a copy of this software and associated documentation
10 ;;; files (the "Software"), to deal in the Software without
11 ;;; restriction, including without limitation the rights to use, copy,
12 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
13 ;;; of the Software, and to permit persons to whom the Software is
14 ;;; furnished to do so, subject to the following conditions:
15 ;;;
16 ;;; The above copyright notice and this permission notice shall be
17 ;;; included in all copies or substantial portions of the Software.
18 ;;;
19 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 ;;; DEALINGS IN THE SOFTWARE.
27 ;;;
29 (in-package #:cffi)
31 ;;;# Built-In Types
33 ;; NOTE: In the C standard there's a "signed-char":
34 ;; https://stackoverflow.com/questions/436513/char-signed-char-char-unsigned-char
35 ;; and "char" may be either signed or unsigned, i.e. treating it as a small int
36 ;; is not wise. At the level of CFFI we can safely ignore this and assume that
37 ;; :char is mapped to "signed-char" by the CL implementation under us.
38 (define-built-in-foreign-type :char)
39 (define-built-in-foreign-type :unsigned-char)
40 (define-built-in-foreign-type :short)
41 (define-built-in-foreign-type :unsigned-short)
42 (define-built-in-foreign-type :int)
43 (define-built-in-foreign-type :unsigned-int)
44 (define-built-in-foreign-type :long)
45 (define-built-in-foreign-type :unsigned-long)
46 (define-built-in-foreign-type :float)
47 (define-built-in-foreign-type :double)
48 (define-built-in-foreign-type :void)
50 #-cffi-sys::no-long-long
51 (progn
52 (define-built-in-foreign-type :long-long)
53 (define-built-in-foreign-type :unsigned-long-long))
55 ;;; Define emulated LONG-LONG types. Needs checking whether we're
56 ;;; using the right sizes on various platforms.
57 ;;;
58 ;;; A possibly better, certainly faster though more intrusive,
59 ;;; alternative is available here:
60 ;;; <http://article.gmane.org/gmane.lisp.cffi.devel/1091>
61 #+cffi-sys::no-long-long
62 (eval-when (:compile-toplevel :load-toplevel :execute)
63 (defclass emulated-llong-type (foreign-type) ())
64 (defmethod foreign-type-size ((tp emulated-llong-type)) 8)
65 (defmethod foreign-type-alignment ((tp emulated-llong-type))
66 ;; better than assuming that the alignment is 8
67 (foreign-type-alignment :long))
68 (defmethod aggregatep ((tp emulated-llong-type)) nil)
70 (define-foreign-type emulated-llong (emulated-llong-type)
72 (:simple-parser :long-long))
74 (define-foreign-type emulated-ullong (emulated-llong-type)
76 (:simple-parser :unsigned-long-long))
78 (defmethod canonicalize ((tp emulated-llong)) :long-long)
79 (defmethod unparse-type ((tp emulated-llong)) :long-long)
80 (defmethod canonicalize ((tp emulated-ullong)) :unsigned-long-long)
81 (defmethod unparse-type ((tp emulated-ullong)) :unsigned-long-long)
83 (defun %emulated-mem-ref-64 (ptr type offset)
84 (let ((value #+big-endian
85 (+ (ash (mem-ref ptr :unsigned-long offset) 32)
86 (mem-ref ptr :unsigned-long (+ offset 4)))
87 #+little-endian
88 (+ (mem-ref ptr :unsigned-long offset)
89 (ash (mem-ref ptr :unsigned-long (+ offset 4)) 32))))
90 (if (and (eq type :long-long) (logbitp 63 value))
91 (lognot (logxor value #xFFFFFFFFFFFFFFFF))
92 value)))
94 (defun %emulated-mem-set-64 (value ptr type offset)
95 (when (and (eq type :long-long) (minusp value))
96 (setq value (lognot (logxor value #xFFFFFFFFFFFFFFFF))))
97 (%mem-set (ldb (byte 32 0) value) ptr :unsigned-long
98 #+big-endian (+ offset 4) #+little-endian offset)
99 (%mem-set (ldb (byte 32 32) value) ptr :unsigned-long
100 #+big-endian offset #+little-endian (+ offset 4))
101 value))
103 ;;; When some lisp other than SCL supports :long-double we should
104 ;;; use #-cffi-sys::no-long-double here instead.
105 #+(and (or ecl scl) long-float) (define-built-in-foreign-type :long-double)
107 (defparameter *possible-float-types* '(:float :double :long-double))
109 (defparameter *other-builtin-types* '(:pointer :void)
110 "List of types other than integer or float built in to CFFI.")
112 (defparameter *built-in-integer-types*
113 (set-difference
114 cffi:*built-in-foreign-types*
115 (append *possible-float-types* *other-builtin-types*))
116 "List of integer types supported by CFFI.")
118 (defparameter *built-in-float-types*
119 (set-difference
120 cffi:*built-in-foreign-types*
121 (append *built-in-integer-types* *other-builtin-types*))
122 "List of real float types supported by CFFI.")
124 ;;;# Foreign Pointers
126 (define-compiler-macro inc-pointer (&whole form pointer offset)
127 (if (and (constantp offset)
128 (eql 0 (eval offset)))
129 pointer
130 form))
132 (define-modify-macro incf-pointer (&optional (offset 1)) inc-pointer)
134 (defun mem-ref (ptr type &optional (offset 0))
135 "Return the value of TYPE at OFFSET bytes from PTR. If TYPE is aggregate,
136 we don't return its 'value' but a pointer to it, which is PTR itself."
137 (let* ((parsed-type (parse-type type))
138 (ctype (canonicalize parsed-type)))
139 #+cffi-sys::no-long-long
140 (when (member ctype '(:long-long :unsigned-long-long))
141 (return-from mem-ref
142 (translate-from-foreign (%emulated-mem-ref-64 ptr ctype offset)
143 parsed-type)))
144 ;; normal branch
145 (if (aggregatep parsed-type)
146 (if (bare-struct-type-p parsed-type)
147 (inc-pointer ptr offset)
148 (translate-from-foreign (inc-pointer ptr offset) parsed-type))
149 (translate-from-foreign (%mem-ref ptr ctype offset) parsed-type))))
151 (define-compiler-macro mem-ref (&whole form ptr type &optional (offset 0))
152 "Compiler macro to open-code MEM-REF when TYPE is constant."
153 (if (constantp type)
154 (let* ((parsed-type (parse-type (eval type)))
155 (ctype (canonicalize parsed-type)))
156 ;; Bail out when using emulated long long types.
157 #+cffi-sys::no-long-long
158 (when (member ctype '(:long-long :unsigned-long-long))
159 (return-from mem-ref form))
160 (if (aggregatep parsed-type)
161 (if (bare-struct-type-p parsed-type)
162 `(inc-pointer ,ptr ,offset)
163 (expand-from-foreign `(inc-pointer ,ptr ,offset) parsed-type))
164 (expand-from-foreign `(%mem-ref ,ptr ,ctype ,offset) parsed-type)))
165 form))
167 (defun mem-set (value ptr type &optional (offset 0))
168 "Set the value of TYPE at OFFSET bytes from PTR to VALUE."
169 (let* ((ptype (parse-type type))
170 (ctype (canonicalize ptype)))
171 #+cffi-sys::no-long-long
172 (when (or (eq ctype :long-long) (eq ctype :unsigned-long-long))
173 (return-from mem-set
174 (%emulated-mem-set-64 (translate-to-foreign value ptype)
175 ptr ctype offset)))
176 (if (aggregatep ptype) ; XXX: backwards incompatible?
177 (translate-into-foreign-memory value ptype (inc-pointer ptr offset))
178 (%mem-set (translate-to-foreign value ptype) ptr ctype offset))))
180 (define-setf-expander mem-ref (ptr type &optional (offset 0) &environment env)
181 "SETF expander for MEM-REF that doesn't rebind TYPE.
182 This is necessary for the compiler macro on MEM-SET to be able
183 to open-code (SETF MEM-REF) forms."
184 (multiple-value-bind (dummies vals newval setter getter)
185 (get-setf-expansion ptr env)
186 (declare (ignore setter newval))
187 ;; if either TYPE or OFFSET are constant, we avoid rebinding them
188 ;; so that the compiler macros on MEM-SET and %MEM-SET work.
189 (with-unique-names (store type-tmp offset-tmp)
190 (values
191 (append (unless (constantp type) (list type-tmp))
192 (unless (constantp offset) (list offset-tmp))
193 dummies)
194 (append (unless (constantp type) (list type))
195 (unless (constantp offset) (list offset))
196 vals)
197 (list store)
198 `(progn
199 (mem-set ,store ,getter
200 ,@(if (constantp type) (list type) (list type-tmp))
201 ,@(if (constantp offset) (list offset) (list offset-tmp)))
202 ,store)
203 `(mem-ref ,getter
204 ,@(if (constantp type) (list type) (list type-tmp))
205 ,@(if (constantp offset) (list offset) (list offset-tmp)))))))
207 (define-compiler-macro mem-set
208 (&whole form value ptr type &optional (offset 0))
209 "Compiler macro to open-code (SETF MEM-REF) when type is constant."
210 (if (constantp type)
211 (let* ((parsed-type (parse-type (eval type)))
212 (ctype (canonicalize parsed-type)))
213 ;; Bail out when using emulated long long types.
214 #+cffi-sys::no-long-long
215 (when (member ctype '(:long-long :unsigned-long-long))
216 (return-from mem-set form))
217 (if (aggregatep parsed-type)
218 (expand-into-foreign-memory
219 value parsed-type `(inc-pointer ,ptr ,offset))
220 `(%mem-set ,(expand-to-foreign value parsed-type)
221 ,ptr ,ctype ,offset)))
222 form))
224 ;;;# Dereferencing Foreign Arrays
226 ;;; Maybe this should be named MEM-SVREF? [2007-02-28 LO]
227 (defun mem-aref (ptr type &optional (index 0))
228 "Like MEM-REF except for accessing 1d arrays."
229 (mem-ref ptr type (* index (foreign-type-size type))))
231 (define-compiler-macro mem-aref (&whole form ptr type &optional (index 0))
232 "Compiler macro to open-code MEM-AREF when TYPE (and eventually INDEX)."
233 (if (constantp type)
234 (if (constantp index)
235 `(mem-ref ,ptr ,type
236 ,(* (eval index) (foreign-type-size (eval type))))
237 `(mem-ref ,ptr ,type (* ,index ,(foreign-type-size (eval type)))))
238 form))
240 (define-setf-expander mem-aref (ptr type &optional (index 0) &environment env)
241 "SETF expander for MEM-AREF."
242 (multiple-value-bind (dummies vals newval setter getter)
243 (get-setf-expansion ptr env)
244 (declare (ignore setter newval))
245 ;; we avoid rebinding type and index, if possible (and if type is not
246 ;; constant, we don't bother about the index), so that the compiler macros
247 ;; on MEM-SET or %MEM-SET can work.
248 (with-unique-names (store type-tmp index-tmp)
249 (values
250 (append (unless (constantp type)
251 (list type-tmp))
252 (unless (and (constantp type) (constantp index))
253 (list index-tmp))
254 dummies)
255 (append (unless (constantp type)
256 (list type))
257 (unless (and (constantp type) (constantp index))
258 (list index))
259 vals)
260 (list store)
261 ;; Here we'll try to calculate the offset from the type and index,
262 ;; or if not possible at least get the type size early.
263 `(progn
264 ,(if (constantp type)
265 (if (constantp index)
266 `(mem-set ,store ,getter ,type
267 ,(* (eval index) (foreign-type-size (eval type))))
268 `(mem-set ,store ,getter ,type
269 (* ,index-tmp ,(foreign-type-size (eval type)))))
270 `(mem-set ,store ,getter ,type-tmp
271 (* ,index-tmp (foreign-type-size ,type-tmp))))
272 ,store)
273 `(mem-aref ,getter
274 ,@(if (constantp type)
275 (list type)
276 (list type-tmp))
277 ,@(if (and (constantp type) (constantp index))
278 (list index)
279 (list index-tmp)))))))
281 (defmethod translate-into-foreign-memory
282 (value (type foreign-pointer-type) pointer)
283 (setf (mem-aref pointer :pointer) value))
285 (defmethod translate-into-foreign-memory
286 (value (type foreign-built-in-type) pointer)
287 (setf (mem-aref pointer (unparse-type type)) value))
289 (defun mem-aptr (ptr type &optional (index 0))
290 "The pointer to the element."
291 (inc-pointer ptr (* index (foreign-type-size type))))
293 (define-compiler-macro mem-aptr (&whole form ptr type &optional (index 0))
294 "The pointer to the element."
295 (cond ((not (constantp type))
296 form)
297 ((not (constantp index))
298 `(inc-pointer ,ptr (* ,index ,(foreign-type-size (eval type)))))
299 ((zerop (eval index))
300 ptr)
302 `(inc-pointer ,ptr ,(* (eval index)
303 (foreign-type-size (eval type)))))))
305 (define-foreign-type foreign-array-type ()
306 ((dimensions :reader dimensions :initarg :dimensions)
307 (element-type :reader element-type :initarg :element-type))
308 (:actual-type :pointer))
310 (defmethod aggregatep ((type foreign-array-type))
313 (defmethod print-object ((type foreign-array-type) stream)
314 "Print a FOREIGN-ARRAY-TYPE instance to STREAM unreadably."
315 (print-unreadable-object (type stream :type t :identity nil)
316 (format stream "~S ~S" (element-type type) (dimensions type))))
318 (defun array-element-size (array-type)
319 (foreign-type-size (element-type array-type)))
321 (defmethod foreign-type-size ((type foreign-array-type))
322 (* (array-element-size type) (reduce #'* (dimensions type))))
324 (defmethod foreign-type-alignment ((type foreign-array-type))
325 (foreign-type-alignment (element-type type)))
327 (define-parse-method :array (element-type &rest dimensions)
328 (assert (plusp (length dimensions)))
329 (make-instance 'foreign-array-type
330 :element-type element-type
331 :dimensions dimensions))
333 (defun indexes-to-row-major-index (dimensions &rest subscripts)
334 (apply #'+ (maplist (lambda (x y)
335 (* (car x) (apply #'* (cdr y))))
336 subscripts
337 dimensions)))
339 (defun row-major-index-to-indexes (index dimensions)
340 (loop with idx = index
341 with rank = (length dimensions)
342 with indexes = (make-list rank)
343 for dim-index from (- rank 1) downto 0 do
344 (setf (values idx (nth dim-index indexes))
345 (floor idx (nth dim-index dimensions)))
346 finally (return indexes)))
348 (defun foreign-alloc (type &key (initial-element nil initial-element-p)
349 (initial-contents nil initial-contents-p)
350 (count 1 count-p) null-terminated-p)
351 "Allocate enough memory to hold COUNT objects of type TYPE. If
352 INITIAL-ELEMENT is supplied, each element of the newly allocated
353 memory is initialized with its value. If INITIAL-CONTENTS is supplied,
354 each of its elements will be used to initialize the contents of the
355 newly allocated memory."
356 (let (contents-length)
357 ;; Some error checking, etc...
358 (when (and null-terminated-p
359 (not (eq (canonicalize-foreign-type type) :pointer)))
360 (error "Cannot use :NULL-TERMINATED-P with non-pointer types."))
361 (when (and initial-element-p initial-contents-p)
362 (error "Cannot specify both :INITIAL-ELEMENT and :INITIAL-CONTENTS"))
363 (when initial-contents-p
364 (setq contents-length (length initial-contents))
365 (if count-p
366 (assert (>= count contents-length))
367 (setq count contents-length)))
368 ;; Everything looks good.
369 (let ((ptr (%foreign-alloc (* (foreign-type-size type)
370 (if null-terminated-p (1+ count) count)))))
371 (when initial-element-p
372 (dotimes (i count)
373 (setf (mem-aref ptr type i) initial-element)))
374 (when initial-contents-p
375 (dotimes (i contents-length)
376 (setf (mem-aref ptr type i) (elt initial-contents i))))
377 (when null-terminated-p
378 (setf (mem-aref ptr :pointer count) (null-pointer)))
379 ptr)))
381 ;;; Simple compiler macro that kicks in when TYPE is constant and only
382 ;;; the COUNT argument is passed. (Note: hard-coding the type's size
383 ;;; into the fasl will likely break CLISP fasl cross-platform
384 ;;; compatibilty.)
385 (define-compiler-macro foreign-alloc (&whole form type &rest args
386 &key (count 1 count-p) &allow-other-keys)
387 (if (or (and count-p (<= (length args) 2)) (null args))
388 (cond
389 ((and (constantp type) (constantp count))
390 `(%foreign-alloc ,(* (eval count) (foreign-type-size (eval type)))))
391 ((constantp type)
392 `(%foreign-alloc (* ,count ,(foreign-type-size (eval type)))))
393 (t form))
394 form))
396 (defun lisp-array-to-foreign (array pointer array-type)
397 "Copy elements from a Lisp array to POINTER. ARRAY-TYPE must be a CFFI array
398 type."
399 (let* ((type (ensure-parsed-base-type array-type))
400 (el-type (element-type type))
401 (dimensions (dimensions type)))
402 (loop with foreign-type-size = (array-element-size type)
403 with size = (reduce #'* dimensions)
404 for i from 0 below size
405 for offset = (* i foreign-type-size)
406 for element = (apply #'aref array
407 (row-major-index-to-indexes i dimensions))
408 do (setf (mem-ref pointer el-type offset) element))))
410 (defun foreign-array-to-lisp (pointer array-type &rest make-array-args)
411 "Copy elements from pointer into a Lisp array. ARRAY-TYPE must be a CFFI array
412 type; the type of the resulting Lisp array can be defined in MAKE-ARRAY-ARGS
413 that are then passed to MAKE-ARRAY. If POINTER is a null pointer, returns NIL."
414 (unless (null-pointer-p pointer)
415 (let* ((type (ensure-parsed-base-type array-type))
416 (el-type (element-type type))
417 (dimensions (dimensions type))
418 (array (apply #'make-array dimensions make-array-args)))
419 (loop with foreign-type-size = (array-element-size type)
420 with size = (reduce #'* dimensions)
421 for i from 0 below size
422 for offset = (* i foreign-type-size)
423 for element = (mem-ref pointer el-type offset)
424 do (setf (apply #'aref array
425 (row-major-index-to-indexes i dimensions))
426 element))
427 array)))
429 (defun foreign-array-alloc (array array-type)
430 "Allocate a foreign array containing the elements of lisp array.
431 The foreign array must be freed with foreign-array-free."
432 (check-type array array)
433 (let* ((type (ensure-parsed-base-type array-type))
434 (ptr (foreign-alloc (element-type type)
435 :count (reduce #'* (dimensions type)))))
436 (lisp-array-to-foreign array ptr array-type)
437 ptr))
439 (defun foreign-array-free (ptr)
440 "Free a foreign array allocated by foreign-array-alloc."
441 (foreign-free ptr))
443 (defmacro with-foreign-array ((var lisp-array array-type) &body body)
444 "Bind var to a foreign array containing lisp-array elements in body."
445 (with-unique-names (type)
446 `(let ((,type (ensure-parsed-base-type ,array-type)))
447 (with-foreign-pointer (,var (* (reduce #'* (dimensions ,type))
448 (array-element-size ,type)))
449 (lisp-array-to-foreign ,lisp-array ,var ,array-type)
450 ,@body))))
452 (defun foreign-aref (ptr array-type &rest indexes)
453 (let* ((type (ensure-parsed-base-type array-type))
454 (offset (* (array-element-size type)
455 (apply #'indexes-to-row-major-index
456 (dimensions type) indexes))))
457 (mem-ref ptr (element-type type) offset)))
459 (defun (setf foreign-aref) (value ptr array-type &rest indexes)
460 (let* ((type (ensure-parsed-base-type array-type))
461 (offset (* (array-element-size type)
462 (apply #'indexes-to-row-major-index
463 (dimensions type) indexes))))
464 (setf (mem-ref ptr (element-type type) offset) value)))
466 ;;; Automatic translations for the :ARRAY type. Notice that these
467 ;;; translators will also invoke the appropriate translators for for
468 ;;; each of the array's elements since that's the normal behaviour of
469 ;;; the FOREIGN-ARRAY-* operators, but there's a FIXME: **it doesn't
470 ;;; free them yet**
472 ;;; This used to be in a separate type but let's experiment with just
473 ;;; one type for a while. [2008-12-30 LO]
475 ;;; FIXME: those ugly invocations of UNPARSE-TYPE suggest that these
476 ;;; foreign array operators should take the type and dimention
477 ;;; arguments "unboxed". [2008-12-31 LO]
479 (defmethod translate-to-foreign (array (type foreign-array-type))
480 (foreign-array-alloc array (unparse-type type)))
482 (defmethod translate-aggregate-to-foreign (ptr value (type foreign-array-type))
483 (lisp-array-to-foreign value ptr (unparse-type type)))
485 (defmethod translate-from-foreign (pointer (type foreign-array-type))
486 (foreign-array-to-lisp pointer (unparse-type type)))
488 (defmethod free-translated-object (pointer (type foreign-array-type) param)
489 (declare (ignore param))
490 (foreign-array-free pointer))
492 ;;;# Foreign Structures
494 ;;;## Foreign Structure Slots
496 (defgeneric foreign-struct-slot-pointer (ptr slot)
497 (:documentation
498 "Get the address of SLOT relative to PTR."))
500 (defgeneric foreign-struct-slot-pointer-form (ptr slot)
501 (:documentation
502 "Return a form to get the address of SLOT in PTR."))
504 (defgeneric foreign-struct-slot-value (ptr slot)
505 (:documentation
506 "Return the value of SLOT in structure PTR."))
508 (defgeneric (setf foreign-struct-slot-value) (value ptr slot)
509 (:documentation
510 "Set the value of a SLOT in structure PTR."))
512 (defgeneric foreign-struct-slot-value-form (ptr slot)
513 (:documentation
514 "Return a form to get the value of SLOT in struct PTR."))
516 (defgeneric foreign-struct-slot-set-form (value ptr slot)
517 (:documentation
518 "Return a form to set the value of SLOT in struct PTR."))
520 (defclass foreign-struct-slot ()
521 ((name :initarg :name :reader slot-name)
522 (offset :initarg :offset :accessor slot-offset)
523 ;; FIXME: the type should probably be parsed?
524 (type :initarg :type :accessor slot-type))
525 (:documentation "Base class for simple and aggregate slots."))
527 (defmethod foreign-struct-slot-pointer (ptr (slot foreign-struct-slot))
528 "Return the address of SLOT relative to PTR."
529 (inc-pointer ptr (slot-offset slot)))
531 (defmethod foreign-struct-slot-pointer-form (ptr (slot foreign-struct-slot))
532 "Return a form to get the address of SLOT relative to PTR."
533 (let ((offset (slot-offset slot)))
534 (if (zerop offset)
536 `(inc-pointer ,ptr ,offset))))
538 (defun foreign-slot-names (type)
539 "Returns a list of TYPE's slot names in no particular order."
540 (loop for value being the hash-values
541 in (slots (ensure-parsed-base-type type))
542 collect (slot-name value)))
544 ;;;### Simple Slots
546 (defclass simple-struct-slot (foreign-struct-slot)
548 (:documentation "Non-aggregate structure slots."))
550 (defmethod foreign-struct-slot-value (ptr (slot simple-struct-slot))
551 "Return the value of a simple SLOT from a struct at PTR."
552 (mem-ref ptr (slot-type slot) (slot-offset slot)))
554 (defmethod foreign-struct-slot-value-form (ptr (slot simple-struct-slot))
555 "Return a form to get the value of a slot from PTR."
556 `(mem-ref ,ptr ',(slot-type slot) ,(slot-offset slot)))
558 (defmethod (setf foreign-struct-slot-value) (value ptr (slot simple-struct-slot))
559 "Set the value of a simple SLOT to VALUE in PTR."
560 (setf (mem-ref ptr (slot-type slot) (slot-offset slot)) value))
562 (defmethod foreign-struct-slot-set-form (value ptr (slot simple-struct-slot))
563 "Return a form to set the value of a simple structure slot."
564 `(setf (mem-ref ,ptr ',(slot-type slot) ,(slot-offset slot)) ,value))
566 ;;;### Aggregate Slots
568 (defclass aggregate-struct-slot (foreign-struct-slot)
569 ((count :initarg :count :accessor slot-count))
570 (:documentation "Aggregate structure slots."))
572 ;;; Since MEM-REF returns a pointer for struct types we are able to
573 ;;; chain together slot names when accessing slot values in nested
574 ;;; structures.
575 (defmethod foreign-struct-slot-value (ptr (slot aggregate-struct-slot))
576 "Return a pointer to SLOT relative to PTR."
577 (convert-from-foreign (inc-pointer ptr (slot-offset slot))
578 (slot-type slot)))
580 (defmethod foreign-struct-slot-value-form (ptr (slot aggregate-struct-slot))
581 "Return a form to get the value of SLOT relative to PTR."
582 `(convert-from-foreign (inc-pointer ,ptr ,(slot-offset slot))
583 ',(slot-type slot)))
585 (defmethod translate-aggregate-to-foreign (ptr value (type foreign-struct-type))
586 ;;; FIXME: use the block memory interface instead.
587 (loop for i below (foreign-type-size type)
588 do (%mem-set (%mem-ref value :char i) ptr :char i)))
590 (defmethod (setf foreign-struct-slot-value)
591 (value ptr (slot aggregate-struct-slot))
592 "Set the value of an aggregate SLOT to VALUE in PTR."
593 (translate-aggregate-to-foreign (inc-pointer ptr (slot-offset slot))
594 value
595 (parse-type (slot-type slot))))
597 (defmethod foreign-struct-slot-set-form (value ptr (slot aggregate-struct-slot))
598 "Return a form to get the value of an aggregate SLOT relative to PTR."
599 `(translate-aggregate-to-foreign (inc-pointer ,ptr ,(slot-offset slot))
600 ,value
601 ,(parse-type (slot-type slot))))
603 ;;;## Defining Foreign Structures
605 (defun make-struct-slot (name offset type count)
606 "Make the appropriate type of structure slot."
607 ;; If TYPE is an aggregate type or COUNT is >1, create an
608 ;; AGGREGATE-STRUCT-SLOT, otherwise a SIMPLE-STRUCT-SLOT.
609 (if (or (> count 1) (aggregatep (parse-type type)))
610 (make-instance 'aggregate-struct-slot :offset offset :type type
611 :name name :count count)
612 (make-instance 'simple-struct-slot :offset offset :type type
613 :name name)))
615 (defun parse-deprecated-struct-type (name struct-or-union)
616 (check-type struct-or-union (member :struct :union))
617 (let* ((struct-type-name `(,struct-or-union ,name))
618 (struct-type (parse-type struct-type-name)))
619 (simple-style-warning
620 "bare references to struct types are deprecated. ~
621 Please use ~S or ~S instead."
622 `(:pointer ,struct-type-name) struct-type-name)
623 (make-instance (class-of struct-type)
624 :alignment (alignment struct-type)
625 :size (size struct-type)
626 :slots (slots struct-type)
627 :name (name struct-type)
628 :bare t)))
630 ;;; Regarding structure alignment, the following ABIs were checked:
631 ;;; - System-V ABI: x86, x86-64, ppc, arm, mips and itanium. (more?)
632 ;;; - Mac OS X ABI Function Call Guide: ppc32, ppc64 and x86.
634 ;;; Rules used here:
636 ;;; 1. "An entire structure or union object is aligned on the same
637 ;;; boundary as its most strictly aligned member."
639 ;;; 2. "Each member is assigned to the lowest available offset with
640 ;;; the appropriate alignment. This may require internal
641 ;;; padding, depending on the previous member."
643 ;;; 3. "A structure's size is increased, if necessary, to make it a
644 ;;; multiple of the alignment. This may require tail padding,
645 ;;; depending on the last member."
647 ;;; Special cases from darwin/ppc32's ABI:
648 ;;; http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/index.html
650 ;;; 4. "The embedding alignment of the first element in a data
651 ;;; structure is equal to the element's natural alignment."
653 ;;; 5. "For subsequent elements that have a natural alignment
654 ;;; greater than 4 bytes, the embedding alignment is 4, unless
655 ;;; the element is a vector." (note: this applies for
656 ;;; structures too)
658 ;; FIXME: get a better name for this. --luis
659 (defun get-alignment (type alignment-type firstp)
660 "Return alignment for TYPE according to ALIGNMENT-TYPE."
661 (declare (ignorable firstp))
662 (ecase alignment-type
663 (:normal #-(and darwin ppc)
664 (foreign-type-alignment type)
665 #+(and darwin ppc)
666 (if firstp
667 (foreign-type-alignment type)
668 (min 4 (foreign-type-alignment type))))))
670 (defun adjust-for-alignment (type offset alignment-type firstp)
671 "Return OFFSET aligned properly for TYPE according to ALIGNMENT-TYPE."
672 (let* ((align (get-alignment type alignment-type firstp))
673 (rem (mod offset align)))
674 (if (zerop rem)
675 offset
676 (+ offset (- align rem)))))
678 (defmacro with-tentative-type-definition ((name value namespace) &body body)
679 (once-only (name namespace)
680 `(unwind-protect-case ()
681 (progn
682 (notice-foreign-type ,name ,value ,namespace)
683 ,@body)
684 (:abort (undefine-foreign-type ,name ,namespace)))))
686 (defun notice-foreign-struct-definition (name options slots)
687 "Parse and install a foreign structure definition."
688 (destructuring-bind (&key size (class 'foreign-struct-type))
689 options
690 (let ((struct (make-instance class :name name))
691 (current-offset 0)
692 (max-offset 0)
693 (max-align 1)
694 (firstp t))
695 (with-tentative-type-definition (name struct :struct)
696 ;; determine offsets
697 (dolist (slotdef slots)
698 (destructuring-bind (slotname type &key (count 1) offset) slotdef
699 (when (eq (canonicalize-foreign-type type) :void)
700 (simple-foreign-type-error type :struct
701 "In struct ~S: void type not allowed in field ~S"
702 name slotdef))
703 (setq current-offset
704 (or offset
705 (adjust-for-alignment type current-offset :normal firstp)))
706 (let* ((slot (make-struct-slot slotname current-offset type count))
707 (align (get-alignment (slot-type slot) :normal firstp)))
708 (setf (gethash slotname (slots struct)) slot)
709 (when (> align max-align)
710 (setq max-align align)))
711 (incf current-offset (* count (foreign-type-size type)))
712 (setf max-offset (max max-offset current-offset)))
713 (setq firstp nil))
714 ;; calculate padding and alignment
715 (setf (alignment struct) max-align) ; See point 1 above.
716 (let ((tail-padding (- max-align (rem max-offset max-align))))
717 (unless (= tail-padding max-align) ; See point 3 above.
718 (incf max-offset tail-padding)))
719 (setf (size struct) (or size max-offset))))))
721 (defun generate-struct-accessors (name conc-name slot-names)
722 (loop with pointer-arg = (symbolicate '#:pointer-to- name)
723 for slot in slot-names
724 for accessor = (symbolicate conc-name slot)
725 collect `(defun ,accessor (,pointer-arg)
726 (foreign-slot-value ,pointer-arg '(:struct ,name) ',slot))
727 collect `(defun (setf ,accessor) (value ,pointer-arg)
728 (foreign-slot-set value ,pointer-arg '(:struct ,name) ',slot))))
730 (define-parse-method :struct (name)
731 (funcall (find-type-parser name :struct)))
733 (defvar *defcstruct-hook* nil)
735 (defmacro defcstruct (name-and-options &body fields)
736 "Define the layout of a foreign structure."
737 (discard-docstring fields)
738 (destructuring-bind (name . options)
739 (ensure-list name-and-options)
740 (let ((conc-name (getf options :conc-name)))
741 (remf options :conc-name)
742 (unless (getf options :class) (setf (getf options :class) (symbolicate name '-tclass)))
743 `(eval-when (:compile-toplevel :load-toplevel :execute)
744 ;; m-f-s-t could do with this with mop:ensure-class.
745 ,(when-let (class (getf options :class))
746 `(defclass ,class (foreign-struct-type
747 translatable-foreign-type)
748 ()))
749 (notice-foreign-struct-definition ',name ',options ',fields)
750 ,@(when conc-name
751 (generate-struct-accessors name conc-name
752 (mapcar #'car fields)))
753 ,@(when *defcstruct-hook*
754 ;; If non-nil, *defcstruct-hook* should be a function
755 ;; of the arguments that returns NIL or a list of
756 ;; forms to include in the expansion.
757 (apply *defcstruct-hook* name-and-options fields))
758 (define-parse-method ,name ()
759 (parse-deprecated-struct-type ',name :struct))
760 '(:struct ,name)))))
762 ;;;## Accessing Foreign Structure Slots
764 (defun get-slot-info (type slot-name)
765 "Return the slot info for SLOT-NAME or raise an error."
766 (let* ((struct (ensure-parsed-base-type type))
767 (info (gethash slot-name (slots struct))))
768 (unless info
769 (simple-foreign-type-error type :struct
770 "Undefined slot ~A in foreign type ~A."
771 slot-name type))
772 info))
774 (defun foreign-slot-pointer (ptr type slot-name)
775 "Return the address of SLOT-NAME in the structure at PTR."
776 (foreign-struct-slot-pointer ptr (get-slot-info type slot-name)))
778 (define-compiler-macro foreign-slot-pointer (&whole whole ptr type slot-name)
779 (if (and (constantp type) (constantp slot-name))
780 (foreign-struct-slot-pointer-form
781 ptr (get-slot-info (eval type) (eval slot-name)))
782 whole))
784 (defun foreign-slot-type (type slot-name)
785 "Return the type of SLOT in a struct TYPE."
786 (slot-type (get-slot-info type slot-name)))
788 (defun foreign-slot-offset (type slot-name)
789 "Return the offset of SLOT in a struct TYPE."
790 (slot-offset (get-slot-info type slot-name)))
792 (defun foreign-slot-count (type slot-name)
793 "Return the number of items in SLOT in a struct TYPE."
794 (slot-count (get-slot-info type slot-name)))
796 (defun foreign-slot-value (ptr type slot-name)
797 "Return the value of SLOT-NAME in the foreign structure at PTR."
798 (foreign-struct-slot-value ptr (get-slot-info type slot-name)))
800 (define-compiler-macro foreign-slot-value (&whole form ptr type slot-name)
801 "Optimizer for FOREIGN-SLOT-VALUE when TYPE is constant."
802 (if (and (constantp type) (constantp slot-name))
803 (foreign-struct-slot-value-form
804 ptr (get-slot-info (eval type) (eval slot-name)))
805 form))
807 (define-setf-expander foreign-slot-value (ptr type slot-name &environment env)
808 "SETF expander for FOREIGN-SLOT-VALUE."
809 (multiple-value-bind (dummies vals newval setter getter)
810 (get-setf-expansion ptr env)
811 (declare (ignore setter newval))
812 (if (and (constantp type) (constantp slot-name))
813 ;; if TYPE and SLOT-NAME are constant we avoid rebinding them
814 ;; so that the compiler macro on FOREIGN-SLOT-SET works.
815 (with-unique-names (store)
816 (values
817 dummies
818 vals
819 (list store)
820 `(progn
821 (foreign-slot-set ,store ,getter ,type ,slot-name)
822 ,store)
823 `(foreign-slot-value ,getter ,type ,slot-name)))
824 ;; if not...
825 (with-unique-names (store slot-name-tmp type-tmp)
826 (values
827 (list* type-tmp slot-name-tmp dummies)
828 (list* type slot-name vals)
829 (list store)
830 `(progn
831 (foreign-slot-set ,store ,getter ,type-tmp ,slot-name-tmp)
832 ,store)
833 `(foreign-slot-value ,getter ,type-tmp ,slot-name-tmp))))))
835 (defun foreign-slot-set (value ptr type slot-name)
836 "Set the value of SLOT-NAME in a foreign structure."
837 (setf (foreign-struct-slot-value ptr (get-slot-info type slot-name)) value))
839 (define-compiler-macro foreign-slot-set
840 (&whole form value ptr type slot-name)
841 "Optimizer when TYPE and SLOT-NAME are constant."
842 (if (and (constantp type) (constantp slot-name))
843 (foreign-struct-slot-set-form
844 value ptr (get-slot-info (eval type) (eval slot-name)))
845 form))
847 (defmacro with-foreign-slots ((vars ptr type) &body body)
848 "Create local symbol macros for each var in VARS to reference
849 foreign slots in PTR of TYPE. Similar to WITH-SLOTS.
850 Each var can be of the form:
851 name name bound to slot of same name
852 (:pointer name) name bound to pointer to slot of same name
853 (name slot-name) name bound to slot-name
854 (name :pointer slot-name) name bound to pointer to slot-name"
855 (let ((ptr-var (gensym "PTR")))
856 `(let ((,ptr-var ,ptr))
857 (symbol-macrolet
858 ,(loop :for var :in vars
859 :collect
860 (if (listp var)
861 (let ((p1 (first var)) (p2 (second var)) (p3 (third var)))
862 (if (eq p1 :pointer)
863 `(,p2 (foreign-slot-pointer ,ptr-var ',type ',p2))
864 (if (eq p2 :pointer)
865 `(,p1 (foreign-slot-pointer ,ptr-var ',type ',p3))
866 `(,p1 (foreign-slot-value ,ptr-var ',type ',p2)))))
867 `(,var (foreign-slot-value ,ptr-var ',type ',var))))
868 ,@body))))
870 ;;; We could add an option to define a struct instead of a class, in
871 ;;; the unlikely event someone needs something like that.
872 (defmacro define-c-struct-wrapper (class-and-type supers &optional slots)
873 "Define a new class with CLOS slots matching those of a foreign
874 struct type. An INITIALIZE-INSTANCE method is defined which
875 takes a :POINTER initarg that is used to store the slots of a
876 foreign object. This pointer is only used for initialization and
877 it is not retained.
879 CLASS-AND-TYPE is either a list of the form (class-name
880 struct-type) or a single symbol naming both. The class will
881 inherit SUPERS. If a list of SLOTS is specified, only those
882 slots will be defined and stored."
883 (destructuring-bind (class-name &optional (struct-type (list :struct class-name)))
884 (ensure-list class-and-type)
885 (let ((slots (or slots (foreign-slot-names struct-type))))
886 `(progn
887 (defclass ,class-name ,supers
888 ,(loop for slot in slots collect
889 `(,slot :reader ,(format-symbol t "~A-~A" class-name slot))))
890 ;; This could be done in a parent class by using
891 ;; FOREIGN-SLOT-NAMES when instantiating but then the compiler
892 ;; macros wouldn't kick in.
893 (defmethod initialize-instance :after ((inst ,class-name) &key pointer)
894 (with-foreign-slots (,slots pointer ,struct-type)
895 ,@(loop for slot in slots collect
896 `(setf (slot-value inst ',slot) ,slot))))
897 ',class-name))))
899 ;;;# Foreign Unions
901 ;;; A union is a subclass of FOREIGN-STRUCT-TYPE in which all slots
902 ;;; have an offset of zero.
904 ;;; See also the notes regarding ABI requirements in
905 ;;; NOTICE-FOREIGN-STRUCT-DEFINITION
906 (defun notice-foreign-union-definition (name-and-options slots)
907 "Parse and install a foreign union definition."
908 (destructuring-bind (name &key size)
909 (ensure-list name-and-options)
910 (let ((union (make-instance 'foreign-union-type :name name))
911 (max-size 0)
912 (max-align 0))
913 (with-tentative-type-definition (name union :union)
914 (dolist (slotdef slots)
915 (destructuring-bind (slotname type &key (count 1)) slotdef
916 (when (eq (canonicalize-foreign-type type) :void)
917 (simple-foreign-type-error name :struct
918 "In union ~S: void type not allowed in field ~S"
919 name slotdef))
920 (let* ((slot (make-struct-slot slotname 0 type count))
921 (size (* count (foreign-type-size type)))
922 (align (foreign-type-alignment (slot-type slot))))
923 (setf (gethash slotname (slots union)) slot)
924 (when (> size max-size)
925 (setf max-size size))
926 (when (> align max-align)
927 (setf max-align align)))))
928 (setf (size union) (or size max-size))
929 (setf (alignment union) max-align)))))
931 (define-parse-method :union (name)
932 (funcall (find-type-parser name :union)))
934 (defmacro defcunion (name-and-options &body fields)
935 "Define the layout of a foreign union."
936 (discard-docstring fields)
937 (destructuring-bind (name &key size)
938 (ensure-list name-and-options)
939 (declare (ignore size))
940 `(eval-when (:compile-toplevel :load-toplevel :execute)
941 (notice-foreign-union-definition ',name-and-options ',fields)
942 (define-parse-method ,name ()
943 (parse-deprecated-struct-type ',name :union))
944 '(:union ,name))))
946 ;;;# Operations on Types
948 (defmethod foreign-type-alignment (type)
949 "Return the alignment in bytes of a foreign type."
950 (foreign-type-alignment (parse-type type)))
952 (defmacro with-foreign-object ((var type &optional (count 1)) &body body)
953 "Bind VAR to a pointer to COUNT objects of TYPE during BODY.
954 The buffer has dynamic extent and may be stack allocated."
955 `(with-foreign-pointer
956 (,var ,(if (constantp type)
957 ;; with-foreign-pointer may benefit from constant folding:
958 (if (constantp count)
959 (* (eval count) (foreign-type-size (eval type)))
960 `(* ,count ,(foreign-type-size (eval type))))
961 `(* ,count (foreign-type-size ,type))))
962 ,@body))
964 (defmacro with-foreign-objects (bindings &body body)
965 (if bindings
966 `(with-foreign-object ,(car bindings)
967 (with-foreign-objects ,(cdr bindings)
968 ,@body))
969 `(progn ,@body)))
971 ;;;## Anonymous Type Translators
973 ;;; (:wrapper :to-c some-function :from-c another-function)
975 ;;; TODO: We will need to add a FREE function to this as well I think.
976 ;;; --james
978 (define-foreign-type foreign-type-wrapper ()
979 ((to-c :initarg :to-c :reader wrapper-to-c)
980 (from-c :initarg :from-c :reader wrapper-from-c))
981 (:documentation "Wrapper type."))
983 (define-parse-method :wrapper (base-type &key to-c from-c)
984 (make-instance 'foreign-type-wrapper
985 :actual-type (parse-type base-type)
986 :to-c (or to-c 'identity)
987 :from-c (or from-c 'identity)))
989 (defmethod translate-to-foreign (value (type foreign-type-wrapper))
990 (translate-to-foreign
991 (funcall (slot-value type 'to-c) value) (actual-type type)))
993 (defmethod translate-from-foreign (value (type foreign-type-wrapper))
994 (funcall (slot-value type 'from-c)
995 (translate-from-foreign value (actual-type type))))
997 ;;;# Other types
999 ;;; Boolean type. Maps to an :int by default. Only accepts integer types.
1000 (define-foreign-type foreign-boolean-type ()
1003 (define-parse-method :boolean (&optional (base-type :int))
1004 (make-instance
1005 'foreign-boolean-type :actual-type
1006 (ecase (canonicalize-foreign-type base-type)
1007 ((:char :unsigned-char :int :unsigned-int :long :unsigned-long
1008 #-cffi-sys::no-long-long :long-long
1009 #-cffi-sys::no-long-long :unsigned-long-long) base-type))))
1011 (defmethod translate-to-foreign (value (type foreign-boolean-type))
1012 (if value 1 0))
1014 (defmethod translate-from-foreign (value (type foreign-boolean-type))
1015 (not (zerop value)))
1017 (defmethod expand-to-foreign (value (type foreign-boolean-type))
1018 "Optimization for the :boolean type."
1019 (if (constantp value)
1020 (if (eval value) 1 0)
1021 `(if ,value 1 0)))
1023 (defmethod expand-from-foreign (value (type foreign-boolean-type))
1024 "Optimization for the :boolean type."
1025 (if (constantp value) ; very unlikely, heh
1026 (not (zerop (eval value)))
1027 `(not (zerop ,value))))
1029 ;;; Boolean type that represents C99 _Bool
1030 (defctype :bool (:boolean :char))
1032 ;;;# Typedefs for built-in types.
1034 (defctype :uchar :unsigned-char)
1035 (defctype :ushort :unsigned-short)
1036 (defctype :uint :unsigned-int)
1037 (defctype :ulong :unsigned-long)
1038 (defctype :llong :long-long)
1039 (defctype :ullong :unsigned-long-long)
1041 (defmacro defctype-matching (name size-or-type base-types &key (match-by '=))
1042 (let* ((target-size (typecase size-or-type
1043 (integer size-or-type)
1044 (t (foreign-type-size size-or-type))))
1045 (matching-type (loop for type in base-types
1046 for size = (foreign-type-size type)
1047 when (funcall match-by target-size size)
1048 return type)))
1049 (if matching-type
1050 `(defctype ,name ,matching-type)
1051 `(warn "Found no matching type of size ~d in~% ~a"
1052 ,target-size ',base-types))))
1054 ;;; We try to define the :[u]int{8,16,32,64} types by looking at
1055 ;;; the sizes of the built-in integer types and defining typedefs.
1056 (macrolet ((match-types (sized-types base-types)
1057 `(progn ,@(loop for (name size-or-type) in sized-types
1058 collect `(defctype-matching ,name ,size-or-type ,base-types)))))
1059 ;; signed
1060 (match-types ((:int8 1) (:int16 2) (:int32 4) (:int64 8)
1061 (:intptr :pointer))
1062 (:char :short :int :long :long-long))
1063 ;; unsigned
1064 (match-types ((:uint8 1) (:uint16 2) (:uint32 4) (:uint64 8)
1065 (:uintptr :pointer))
1066 (:unsigned-char :unsigned-short :unsigned-int :unsigned-long
1067 :unsigned-long-long)))
1069 ;;; Pretty safe bets.
1070 (defctype :size #+64-bit :uint64 #+32-bit :uint32)
1071 (defctype :ssize #+64-bit :int64 #+32-bit :int32)
1072 (defctype :ptrdiff :ssize)
1073 (defctype :offset #+(or 64-bit bsd) :int64 #-(or 64-bit bsd) :int32)