Add compiler macro utils CONSTANT-FORM-P and CONSTANT-FORM-VALUE
[cffi.git] / src / types.lisp
blobaa01a3ea63f81a5a17008915dcfe88297a071962
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 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-align 1)
693 (firstp t))
694 (with-tentative-type-definition (name struct :struct)
695 ;; determine offsets
696 (dolist (slotdef slots)
697 (destructuring-bind (slotname type &key (count 1) offset) slotdef
698 (when (eq (canonicalize-foreign-type type) :void)
699 (simple-foreign-type-error type :struct
700 "In struct ~S: void type not allowed in field ~S"
701 name slotdef))
702 (setq current-offset
703 (or offset
704 (adjust-for-alignment type current-offset :normal firstp)))
705 (let* ((slot (make-struct-slot slotname current-offset type count))
706 (align (get-alignment (slot-type slot) :normal firstp)))
707 (setf (gethash slotname (slots struct)) slot)
708 (when (> align max-align)
709 (setq max-align align)))
710 (incf current-offset (* count (foreign-type-size type))))
711 (setq firstp nil))
712 ;; calculate padding and alignment
713 (setf (alignment struct) max-align) ; See point 1 above.
714 (let ((tail-padding (- max-align (rem current-offset max-align))))
715 (unless (= tail-padding max-align) ; See point 3 above.
716 (incf current-offset tail-padding)))
717 (setf (size struct) (or size current-offset))))))
719 (defun generate-struct-accessors (name conc-name slot-names)
720 (loop with pointer-arg = (symbolicate '#:pointer-to- name)
721 for slot in slot-names
722 for accessor = (symbolicate conc-name slot)
723 collect `(defun ,accessor (,pointer-arg)
724 (foreign-slot-value ,pointer-arg '(:struct ,name) ',slot))
725 collect `(defun (setf ,accessor) (value ,pointer-arg)
726 (foreign-slot-set value ,pointer-arg '(:struct ,name) ',slot))))
728 (define-parse-method :struct (name)
729 (funcall (find-type-parser name :struct)))
731 (defvar *defcstruct-hook* nil)
733 (defmacro defcstruct (name-and-options &body fields)
734 "Define the layout of a foreign structure."
735 (discard-docstring fields)
736 (destructuring-bind (name . options)
737 (ensure-list name-and-options)
738 (let ((conc-name (getf options :conc-name)))
739 (remf options :conc-name)
740 (unless (getf options :class) (setf (getf options :class) (symbolicate name '-tclass)))
741 `(eval-when (:compile-toplevel :load-toplevel :execute)
742 ;; m-f-s-t could do with this with mop:ensure-class.
743 ,(when-let (class (getf options :class))
744 `(defclass ,class (foreign-struct-type
745 translatable-foreign-type)
746 ()))
747 (notice-foreign-struct-definition ',name ',options ',fields)
748 ,@(when conc-name
749 (generate-struct-accessors name conc-name
750 (mapcar #'car fields)))
751 ,@(when *defcstruct-hook*
752 ;; If non-nil, *defcstruct-hook* should be a function
753 ;; of the arguments that returns NIL or a list of
754 ;; forms to include in the expansion.
755 (apply *defcstruct-hook* name-and-options fields))
756 (define-parse-method ,name ()
757 (parse-deprecated-struct-type ',name :struct))
758 '(:struct ,name)))))
760 ;;;## Accessing Foreign Structure Slots
762 (defun get-slot-info (type slot-name)
763 "Return the slot info for SLOT-NAME or raise an error."
764 (let* ((struct (ensure-parsed-base-type type))
765 (info (gethash slot-name (slots struct))))
766 (unless info
767 (simple-foreign-type-error type :struct
768 "Undefined slot ~A in foreign type ~A."
769 slot-name type))
770 info))
772 (defun foreign-slot-pointer (ptr type slot-name)
773 "Return the address of SLOT-NAME in the structure at PTR."
774 (foreign-struct-slot-pointer ptr (get-slot-info type slot-name)))
776 (define-compiler-macro foreign-slot-pointer (&whole whole ptr type slot-name)
777 (if (and (constantp type) (constantp slot-name))
778 (foreign-struct-slot-pointer-form
779 ptr (get-slot-info (eval type) (eval slot-name)))
780 whole))
782 (defun foreign-slot-type (type slot-name)
783 "Return the type of SLOT in a struct TYPE."
784 (slot-type (get-slot-info type slot-name)))
786 (defun foreign-slot-offset (type slot-name)
787 "Return the offset of SLOT in a struct TYPE."
788 (slot-offset (get-slot-info type slot-name)))
790 (defun foreign-slot-count (type slot-name)
791 "Return the number of items in SLOT in a struct TYPE."
792 (slot-count (get-slot-info type slot-name)))
794 (defun foreign-slot-value (ptr type slot-name)
795 "Return the value of SLOT-NAME in the foreign structure at PTR."
796 (foreign-struct-slot-value ptr (get-slot-info type slot-name)))
798 (define-compiler-macro foreign-slot-value (&whole form ptr type slot-name)
799 "Optimizer for FOREIGN-SLOT-VALUE when TYPE is constant."
800 (if (and (constantp type) (constantp slot-name))
801 (foreign-struct-slot-value-form
802 ptr (get-slot-info (eval type) (eval slot-name)))
803 form))
805 (define-setf-expander foreign-slot-value (ptr type slot-name &environment env)
806 "SETF expander for FOREIGN-SLOT-VALUE."
807 (multiple-value-bind (dummies vals newval setter getter)
808 (get-setf-expansion ptr env)
809 (declare (ignore setter newval))
810 (if (and (constantp type) (constantp slot-name))
811 ;; if TYPE and SLOT-NAME are constant we avoid rebinding them
812 ;; so that the compiler macro on FOREIGN-SLOT-SET works.
813 (with-unique-names (store)
814 (values
815 dummies
816 vals
817 (list store)
818 `(progn
819 (foreign-slot-set ,store ,getter ,type ,slot-name)
820 ,store)
821 `(foreign-slot-value ,getter ,type ,slot-name)))
822 ;; if not...
823 (with-unique-names (store slot-name-tmp type-tmp)
824 (values
825 (list* type-tmp slot-name-tmp dummies)
826 (list* type slot-name vals)
827 (list store)
828 `(progn
829 (foreign-slot-set ,store ,getter ,type-tmp ,slot-name-tmp)
830 ,store)
831 `(foreign-slot-value ,getter ,type-tmp ,slot-name-tmp))))))
833 (defun foreign-slot-set (value ptr type slot-name)
834 "Set the value of SLOT-NAME in a foreign structure."
835 (setf (foreign-struct-slot-value ptr (get-slot-info type slot-name)) value))
837 (define-compiler-macro foreign-slot-set
838 (&whole form value ptr type slot-name)
839 "Optimizer when TYPE and SLOT-NAME are constant."
840 (if (and (constantp type) (constantp slot-name))
841 (foreign-struct-slot-set-form
842 value ptr (get-slot-info (eval type) (eval slot-name)))
843 form))
845 (defmacro with-foreign-slots ((vars ptr type) &body body)
846 "Create local symbol macros for each var in VARS to reference
847 foreign slots in PTR of TYPE. Similar to WITH-SLOTS.
848 Each var can be of the form:
849 name name bound to slot of same name
850 (:pointer name) name bound to pointer to slot of same name
851 (name slot-name) name bound to slot-name
852 (name :pointer slot-name) name bound to pointer to slot-name"
853 (let ((ptr-var (gensym "PTR")))
854 `(let ((,ptr-var ,ptr))
855 (symbol-macrolet
856 ,(loop :for var :in vars
857 :collect
858 (if (listp var)
859 (let ((p1 (first var)) (p2 (second var)) (p3 (third var)))
860 (if (eq p1 :pointer)
861 `(,p2 (foreign-slot-pointer ,ptr-var ',type ',p2))
862 (if (eq p2 :pointer)
863 `(,p1 (foreign-slot-pointer ,ptr-var ',type ',p3))
864 `(,p1 (foreign-slot-value ,ptr-var ',type ',p2)))))
865 `(,var (foreign-slot-value ,ptr-var ',type ',var))))
866 ,@body))))
868 ;;; We could add an option to define a struct instead of a class, in
869 ;;; the unlikely event someone needs something like that.
870 (defmacro define-c-struct-wrapper (class-and-type supers &optional slots)
871 "Define a new class with CLOS slots matching those of a foreign
872 struct type. An INITIALIZE-INSTANCE method is defined which
873 takes a :POINTER initarg that is used to store the slots of a
874 foreign object. This pointer is only used for initialization and
875 it is not retained.
877 CLASS-AND-TYPE is either a list of the form (class-name
878 struct-type) or a single symbol naming both. The class will
879 inherit SUPERS. If a list of SLOTS is specified, only those
880 slots will be defined and stored."
881 (destructuring-bind (class-name &optional (struct-type (list :struct class-name)))
882 (ensure-list class-and-type)
883 (let ((slots (or slots (foreign-slot-names struct-type))))
884 `(progn
885 (defclass ,class-name ,supers
886 ,(loop for slot in slots collect
887 `(,slot :reader ,(format-symbol t "~A-~A" class-name slot))))
888 ;; This could be done in a parent class by using
889 ;; FOREIGN-SLOT-NAMES when instantiating but then the compiler
890 ;; macros wouldn't kick in.
891 (defmethod initialize-instance :after ((inst ,class-name) &key pointer)
892 (with-foreign-slots (,slots pointer ,struct-type)
893 ,@(loop for slot in slots collect
894 `(setf (slot-value inst ',slot) ,slot))))
895 ',class-name))))
897 ;;;# Foreign Unions
899 ;;; A union is a subclass of FOREIGN-STRUCT-TYPE in which all slots
900 ;;; have an offset of zero.
902 ;;; See also the notes regarding ABI requirements in
903 ;;; NOTICE-FOREIGN-STRUCT-DEFINITION
904 (defun notice-foreign-union-definition (name-and-options slots)
905 "Parse and install a foreign union definition."
906 (destructuring-bind (name &key size)
907 (ensure-list name-and-options)
908 (let ((union (make-instance 'foreign-union-type :name name))
909 (max-size 0)
910 (max-align 0))
911 (with-tentative-type-definition (name union :union)
912 (dolist (slotdef slots)
913 (destructuring-bind (slotname type &key (count 1)) slotdef
914 (when (eq (canonicalize-foreign-type type) :void)
915 (simple-foreign-type-error name :struct
916 "In union ~S: void type not allowed in field ~S"
917 name slotdef))
918 (let* ((slot (make-struct-slot slotname 0 type count))
919 (size (* count (foreign-type-size type)))
920 (align (foreign-type-alignment (slot-type slot))))
921 (setf (gethash slotname (slots union)) slot)
922 (when (> size max-size)
923 (setf max-size size))
924 (when (> align max-align)
925 (setf max-align align)))))
926 (setf (size union) (or size max-size))
927 (setf (alignment union) max-align)))))
929 (define-parse-method :union (name)
930 (funcall (find-type-parser name :union)))
932 (defmacro defcunion (name-and-options &body fields)
933 "Define the layout of a foreign union."
934 (discard-docstring fields)
935 (destructuring-bind (name &key size)
936 (ensure-list name-and-options)
937 (declare (ignore size))
938 `(eval-when (:compile-toplevel :load-toplevel :execute)
939 (notice-foreign-union-definition ',name-and-options ',fields)
940 (define-parse-method ,name ()
941 (parse-deprecated-struct-type ',name :union))
942 '(:union ,name))))
944 ;;;# Operations on Types
946 (defmethod foreign-type-alignment (type)
947 "Return the alignment in bytes of a foreign type."
948 (foreign-type-alignment (parse-type type)))
950 (defmacro with-foreign-object ((var type &optional (count 1)) &body body)
951 "Bind VAR to a pointer to COUNT objects of TYPE during BODY.
952 The buffer has dynamic extent and may be stack allocated."
953 `(with-foreign-pointer
954 (,var ,(if (constantp type)
955 ;; with-foreign-pointer may benefit from constant folding:
956 (if (constantp count)
957 (* (eval count) (foreign-type-size (eval type)))
958 `(* ,count ,(foreign-type-size (eval type))))
959 `(* ,count (foreign-type-size ,type))))
960 ,@body))
962 (defmacro with-foreign-objects (bindings &body body)
963 (if bindings
964 `(with-foreign-object ,(car bindings)
965 (with-foreign-objects ,(cdr bindings)
966 ,@body))
967 `(progn ,@body)))
969 ;;;## Anonymous Type Translators
971 ;;; (:wrapper :to-c some-function :from-c another-function)
973 ;;; TODO: We will need to add a FREE function to this as well I think.
974 ;;; --james
976 (define-foreign-type foreign-type-wrapper ()
977 ((to-c :initarg :to-c :reader wrapper-to-c)
978 (from-c :initarg :from-c :reader wrapper-from-c))
979 (:documentation "Wrapper type."))
981 (define-parse-method :wrapper (base-type &key to-c from-c)
982 (make-instance 'foreign-type-wrapper
983 :actual-type (parse-type base-type)
984 :to-c (or to-c 'identity)
985 :from-c (or from-c 'identity)))
987 (defmethod translate-to-foreign (value (type foreign-type-wrapper))
988 (translate-to-foreign
989 (funcall (slot-value type 'to-c) value) (actual-type type)))
991 (defmethod translate-from-foreign (value (type foreign-type-wrapper))
992 (funcall (slot-value type 'from-c)
993 (translate-from-foreign value (actual-type type))))
995 ;;;# Other types
997 ;;; Boolean type. Maps to an :int by default. Only accepts integer types.
998 (define-foreign-type foreign-boolean-type ()
1001 (define-parse-method :boolean (&optional (base-type :int))
1002 (make-instance
1003 'foreign-boolean-type :actual-type
1004 (ecase (canonicalize-foreign-type base-type)
1005 ((:char :unsigned-char :int :unsigned-int :long :unsigned-long
1006 #-cffi-sys::no-long-long :long-long
1007 #-cffi-sys::no-long-long :unsigned-long-long) base-type))))
1009 (defmethod translate-to-foreign (value (type foreign-boolean-type))
1010 (if value 1 0))
1012 (defmethod translate-from-foreign (value (type foreign-boolean-type))
1013 (not (zerop value)))
1015 (defmethod expand-to-foreign (value (type foreign-boolean-type))
1016 "Optimization for the :boolean type."
1017 (if (constantp value)
1018 (if (eval value) 1 0)
1019 `(if ,value 1 0)))
1021 (defmethod expand-from-foreign (value (type foreign-boolean-type))
1022 "Optimization for the :boolean type."
1023 (if (constantp value) ; very unlikely, heh
1024 (not (zerop (eval value)))
1025 `(not (zerop ,value))))
1027 ;;; Boolean type that represents C99 _Bool
1028 (defctype :bool (:boolean :char))
1030 ;;;# Typedefs for built-in types.
1032 (defctype :uchar :unsigned-char)
1033 (defctype :ushort :unsigned-short)
1034 (defctype :uint :unsigned-int)
1035 (defctype :ulong :unsigned-long)
1036 (defctype :llong :long-long)
1037 (defctype :ullong :unsigned-long-long)
1039 (defmacro defctype-matching (name size-or-type base-types &key (match-by '=))
1040 (let* ((target-size (typecase size-or-type
1041 (integer size-or-type)
1042 (t (foreign-type-size size-or-type))))
1043 (matching-type (loop for type in base-types
1044 for size = (foreign-type-size type)
1045 when (funcall match-by target-size size)
1046 return type)))
1047 (if matching-type
1048 `(defctype ,name ,matching-type)
1049 `(warn "Found no matching type of size ~d in~% ~a"
1050 ,target-size ',base-types))))
1052 ;;; We try to define the :[u]int{8,16,32,64} types by looking at
1053 ;;; the sizes of the built-in integer types and defining typedefs.
1054 (macrolet ((match-types (sized-types base-types)
1055 `(progn ,@(loop for (name size-or-type) in sized-types
1056 collect `(defctype-matching ,name ,size-or-type ,base-types)))))
1057 ;; signed
1058 (match-types ((:int8 1) (:int16 2) (:int32 4) (:int64 8)
1059 (:intptr :pointer))
1060 (:char :short :int :long :long-long))
1061 ;; unsigned
1062 (match-types ((:uint8 1) (:uint16 2) (:uint32 4) (:uint64 8)
1063 (:uintptr :pointer))
1064 (:unsigned-char :unsigned-short :unsigned-int :unsigned-long
1065 :unsigned-long-long)))
1067 ;;; Pretty safe bets.
1068 (defctype :size #+64-bit :uint64 #+32-bit :uint32)
1069 (defctype :ssize #+64-bit :int64 #+32-bit :int32)
1070 (defctype :ptrdiff :ssize)
1071 (defctype :offset #+(or 64-bit bsd) :int64 #-(or 64-bit bsd) :int32)