chiark / gitweb /
Stock item bindings updated to Gtk+ 2.8
[clg] / glib / ffi.lisp
CommitLineData
55212af1 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 1999-2005 Espen S. Johnsen <espen@users.sf.net>
fc358945 3;;
55212af1 4;; Permission is hereby granted, free of charge, to any person obtaining
5;; a copy of this software and associated documentation files (the
6;; "Software"), to deal in the Software without restriction, including
7;; without limitation the rights to use, copy, modify, merge, publish,
8;; distribute, sublicense, and/or sell copies of the Software, and to
9;; permit persons to whom the Software is furnished to do so, subject to
10;; the following conditions:
fc358945 11;;
55212af1 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
fc358945 14;;
55212af1 15;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
fb9bc912 23;; $Id: ffi.lisp,v 1.28 2006/02/26 16:12:25 espen Exp $
fc358945 24
25(in-package "GLIB")
26
fc358945 27
28;;;; Foreign function call interface
29
30(defvar *package-prefix* nil)
31
32(defun set-package-prefix (prefix &optional (package *package*))
33 (let ((package (find-package package)))
7da01daf 34 (setq *package-prefix* (delete package *package-prefix* :key #'car))
fc358945 35 (push (cons package prefix) *package-prefix*))
36 prefix)
37
38(defun package-prefix (&optional (package *package*))
39 (let ((package (find-package package)))
40 (or
41 (cdr (assoc package *package-prefix*))
42 (substitute #\_ #\- (string-downcase (package-name package))))))
43
44(defun find-prefix-package (prefix)
45 (or
46 (car (rassoc (string-downcase prefix) *package-prefix* :test #'string=))
47 (find-package (string-upcase prefix))))
48
49(defmacro use-prefix (prefix &optional (package *package*))
50 `(eval-when (:compile-toplevel :load-toplevel :execute)
51 (set-package-prefix ,prefix ,package)))
52
53
54(defun default-alien-fname (lisp-name)
58ddfaac 55 (let* ((name (substitute #\_ #\- (string-downcase lisp-name)))
56 (stripped-name
57 (cond
58 ((and
59 (char= (char name 0) #\%)
60 (string= "_p" name :start2 (- (length name) 2)))
61 (subseq name 1 (- (length name) 2)))
62 ((char= (char name 0) #\%)
63 (subseq name 1))
64 ((string= "_p" name :start2 (- (length name) 2))
65 (subseq name 0 (- (length name) 2)))
66 (name)))
67 (prefix (package-prefix *package*)))
fc358945 68 (if (or (not prefix) (string= prefix ""))
58ddfaac 69 stripped-name
70 (format nil "~A_~A" prefix stripped-name))))
fc358945 71
72(defun default-alien-type-name (type-name)
73 (let ((prefix (package-prefix *package*)))
74 (apply
75 #'concatenate
76 'string
77 (mapcar
78 #'string-capitalize
79 (cons prefix (split-string (symbol-name type-name) #\-))))))
80
81(defun default-type-name (alien-name)
82 (let ((parts
83 (mapcar
84 #'string-upcase
85 (split-string-if alien-name #'upper-case-p))))
86 (intern
87 (concatenate-strings
88 (rest parts) #\-) (find-prefix-package (first parts)))))
89
90
6baf860c 91(defmacro defbinding (name lambda-list return-type &rest docs/args)
fc358945 92 (multiple-value-bind (lisp-name c-name)
93 (if (atom name)
94 (values name (default-alien-fname name))
95 (values-list name))
96
97 (let ((supplied-lambda-list lambda-list)
98 (docs nil)
99 (args nil))
100 (dolist (doc/arg docs/args)
101 (if (stringp doc/arg)
102 (push doc/arg docs)
103 (progn
104 (destructuring-bind (expr type &optional (style :in)) doc/arg
6cb19a68 105 (unless (member style '(:in :out :in-out :return))
fc358945 106 (error "Bogus argument style ~S in ~S." style doc/arg))
107 (when (and
108 (not supplied-lambda-list)
6cb19a68 109 (namep expr) (member style '(:in :in-out :return)))
fc358945 110 (push expr lambda-list))
e37c4285 111 (push (list (cond
112 ((and (namep expr) (eq style :out)) expr)
113 ((namep expr) (make-symbol (string expr)))
114 ((gensym)))
4d1fea77 115 expr type style) args)))))
fc358945 116
117 (%defbinding
118 c-name lisp-name (or supplied-lambda-list (nreverse lambda-list))
6baf860c 119 return-type (reverse docs) (reverse args)))))
fc358945 120
3d36c5d6 121#+(or cmu sbcl)
6baf860c 122(defun %defbinding (foreign-name lisp-name lambda-list return-type docs args)
3d36c5d6 123 (collect ((alien-types) (alien-bindings) (alien-parameters)
124 (return-values) (cleanup-forms))
fc358945 125 (dolist (arg args)
6baf860c 126 (destructuring-bind (var expr type style) arg
127 (let ((declaration (alien-type type))
4d1fea77 128 (cleanup (cleanup-form type var)))
6baf860c 129
fc358945 130 (cond
6cb19a68 131 ((member style '(:out :in-out))
132 (alien-types `(* ,declaration))
133 (alien-parameters `(addr ,var))
134 (alien-bindings
135 `(,var ,declaration
4eac8484 136 ,@(cond
4d1fea77 137 ((eq style :in-out) (list (to-alien-form type expr)))
4eac8484 138 ((eq declaration 'system-area-pointer)
139 (list '(make-pointer 0))))))
4d1fea77 140 (return-values (from-alien-form type var)))
6cb19a68 141 ((eq style :return)
142 (alien-types declaration)
143 (alien-bindings
4d1fea77 144 `(,var ,declaration ,(to-alien-form type expr)))
6cb19a68 145 (alien-parameters var)
4d1fea77 146 (return-values (from-alien-form type var)))
6cb19a68 147 (cleanup
148 (alien-types declaration)
149 (alien-bindings
4d1fea77 150 `(,var ,declaration ,(to-alien-form type expr)))
6cb19a68 151 (alien-parameters var)
152 (cleanup-forms cleanup))
153 (t
154 (alien-types declaration)
4d1fea77 155 (alien-parameters (to-alien-form type expr)))))))
fc358945 156
157 (let* ((alien-name (make-symbol (string lisp-name)))
158 (alien-funcall `(alien-funcall ,alien-name ,@(alien-parameters))))
159 `(defun ,lisp-name ,lambda-list
160 ,@docs
3d36c5d6 161 #+cmu(declare (optimize (inhibit-warnings 3)))
162 #+sbcl(declare (muffle-conditions compiler-note))
fc358945 163 (with-alien ((,alien-name
164 (function
6baf860c 165 ,(alien-type return-type)
fc358945 166 ,@(alien-types))
167 :extern ,foreign-name)
168 ,@(alien-bindings))
6baf860c 169 ,(if return-type
170 `(values
171 (unwind-protect
4d1fea77 172 ,(from-alien-form return-type alien-funcall)
6baf860c 173 ,@(cleanup-forms))
6cb19a68 174 ,@(return-values))
fc358945 175 `(progn
6baf860c 176 (unwind-protect
177 ,alien-funcall
178 ,@(cleanup-forms))
6cb19a68 179 (values ,@(return-values)))))))))
fc358945 180
181
6baf860c 182;;; Creates bindings at runtime
fc358945 183(defun mkbinding (name return-type &rest arg-types)
3d36c5d6 184 #+cmu(declare (optimize (inhibit-warnings 3)))
185 #+sbcl(declare (muffle-conditions compiler-note))
6baf860c 186 (let* ((ftype
187 `(function ,@(mapcar #'alien-type (cons return-type arg-types))))
fc358945 188 (alien
3d36c5d6 189 (%heap-alien
190 (make-heap-alien-info
191 :type (parse-alien-type ftype #+sbcl nil)
a9392506 192 :sap-form (let ((address (foreign-symbol-address name)))
193 (etypecase address
194 (integer (int-sap address))
195 (system-area-pointer address))))))
6baf860c 196 (translate-arguments (mapcar #'to-alien-function arg-types))
197 (translate-return-value (from-alien-function return-type))
198 (cleanup-arguments (mapcar #'cleanup-function arg-types)))
199
fc358945 200 #'(lambda (&rest args)
201 (map-into args #'funcall translate-arguments args)
202 (prog1
6baf860c 203 (funcall translate-return-value
3d36c5d6 204 (apply #'alien-funcall alien args))
fc358945 205 (mapc #'funcall cleanup-arguments args)))))
206
7bde5a67 207
3d36c5d6 208
ae17423c 209;;;; C callbacks
210
211(defmacro define-callback (name return-type args &body body)
212 (let ((define-callback
213 #+cmu'alien:def-callback
214 #+(and sbcl alien-callbacks)'sb-alien::define-alien-callback
215 #+(and sbcl (not alien-callbacks))'sb-alien:define-alien-function))
216 (multiple-value-bind (doc declaration body)
217 (cond
218 ((and (stringp (first body)) (eq (cadr body) 'declare))
219 (values (first body) (second body) (cddr body)))
220 ((stringp (first body))
221 (values (first body) nil (rest body)))
222 ((eq (caar body) 'declare)
223 (values nil (first body) (rest body)))
224 (t (values nil nil body)))
4d1fea77 225 `(progn
226 #+cmu(defparameter ,name nil)
227 (,define-callback ,name
228 #+(and sbcl alien-callbacks),(alien-type return-type)
229 (#+(or cmu (and sbcl (not alien-callbacks))),(alien-type return-type)
230 ,@(mapcar #'(lambda (arg)
231 (destructuring-bind (name type) arg
232 `(,name ,(alien-type type))))
233 args))
234 ,@(when doc (list doc))
235 ,(to-alien-form return-type
236 `(let (,@(loop
237 for (name type) in args
238 as from-alien-form = (callback-from-alien-form type name)
239 collect `(,name ,from-alien-form)))
240 ,@(when declaration (list declaration))
241 (unwind-protect
242 (progn ,@body)
243 ,@(loop
ae17423c 244 for (name type) in args
4d1fea77 245 do (callback-cleanup-form type name))))))))))
ae17423c 246
247(defun callback-address (callback)
248 #+cmu(alien::callback-trampoline callback)
249 #+(and sbcl (not alien-callbacks))(sb-alien:alien-function-sap callback)
250 #+(and sbcl alien-callbacks)(sb-alien:alien-sap callback))
7bde5a67 251
7aa45361 252#+sbcl
ae17423c 253(deftype callback ()
254 #-alien-callbacks'sb-alien:alien-function
255 #+alien-callbacks'sb-alien:alien)
256
257
258;;; These are for backward compatibility
259
260(defmacro defcallback (name (return-type &rest args) &body body)
261 `(define-callback ,name ,return-type ,args ,@body))
262
263#-cmu
264(defun callback (callback)
265 (callback-address callback))
266
267
fc358945 268
4d1fea77 269;;;; The "type method" system
270
271(defun find-applicable-type-method (name type-spec &optional (error-p t))
272 (let ((type-methods (get name 'type-methods)))
273 (labels ((search-method-in-cpl-order (classes)
274 (when classes
275 (or
276 (gethash (class-name (first classes)) type-methods)
277 (search-method-in-cpl-order (rest classes)))))
278 (lookup-method (type-spec)
279 (if (and (symbolp type-spec) (find-class type-spec nil))
280 (search-method-in-cpl-order
281 (class-precedence-list (find-class type-spec)))
282 (or
283 (let ((specifier (etypecase type-spec
284 (symbol type-spec)
285 (list (first type-spec)))))
286 (gethash specifier type-methods))
287 (multiple-value-bind (expanded-type expanded-p)
288 (type-expand-1 type-spec)
289 (when expanded-p
290 (lookup-method expanded-type))))))
291 (search-built-in-type-hierarchy (sub-tree)
292 (when (subtypep type-spec (first sub-tree))
293 (or
294 (search-nodes (cddr sub-tree))
295 (second sub-tree))))
296 (search-nodes (nodes)
297 (loop
298 for node in nodes
299 as function = (search-built-in-type-hierarchy node)
300 until function
301 finally (return function))))
302 (or
303 (lookup-method type-spec)
304 ;; This is to handle unexpandable types whichs doesn't name a class
305 (unless (and (symbolp type-spec) (find-class type-spec nil))
306 (search-nodes (get name 'built-in-type-hierarchy)))
307 (and
308 error-p
309 (error "No applicable type method for ~A when call width type specifier ~A" name type-spec))))))
310
311
312(defun insert-type-in-hierarchy (specifier function nodes)
313 (cond
314 ((let ((node (find specifier nodes :key #'first)))
315 (when node
316 (setf (second node) function)
317 nodes)))
318 ((let ((node
319 (find-if
320 #'(lambda (node)
321 (subtypep specifier (first node)))
322 nodes)))
323 (when node
324 (setf (cddr node)
325 (insert-type-in-hierarchy specifier function (cddr node)))
326 nodes)))
327 ((let ((sub-nodes (remove-if-not
328 #'(lambda (node)
329 (subtypep (first node) specifier))
330 nodes)))
331 (cons
332 (list* specifier function sub-nodes)
333 (nset-difference nodes sub-nodes))))))
334
335
336(defun add-type-method (name specifier function)
337 (setf (gethash specifier (get name 'type-methods)) function)
338 (when (typep (find-class specifier nil) 'built-in-class)
339 (setf (get name 'built-in-type-hierarchy)
340 (insert-type-in-hierarchy specifier function
341 (get name 'built-in-type-hierarchy)))))
342
343
344;; TODO: handle optional, key and rest arguments
345(defmacro define-type-generic (name lambda-list &optional documentation)
346 (if (or
347 (not lambda-list)
348 (find (first lambda-list) '(&optional &key &rest &allow-other-keys)))
349 (error "A type generic needs at least one required argument")
350 `(progn
351 (setf (get ',name 'type-methods) (make-hash-table))
352 (setf (get ',name 'built-in-type-hierarchy) ())
353 (defun ,name ,lambda-list
354 ,documentation
355 (funcall
356 (find-applicable-type-method ',name ,(first lambda-list))
357 ,@lambda-list)))))
358
359
360(defmacro define-type-method (name lambda-list &body body)
361 (let ((specifier (cadar lambda-list))
362 (args (cons (caar lambda-list) (rest lambda-list))))
363 `(progn
364 (add-type-method ',name ',specifier #'(lambda ,args ,@body))
365 ',name)))
366
367
368
369;;;; Definitons and translations of fundamental types
370
371(define-type-generic alien-type (type-spec))
372(define-type-generic size-of (type-spec))
373(define-type-generic to-alien-form (type-spec form))
374(define-type-generic from-alien-form (type-spec form))
375(define-type-generic cleanup-form (type-spec form)
6baf860c 376 "Creates a form to clean up after the alien call has finished.")
4d1fea77 377(define-type-generic callback-from-alien-form (type-spec form))
378(define-type-generic callback-cleanup-form (type-spec form))
fc358945 379
4d1fea77 380(define-type-generic to-alien-function (type-spec))
381(define-type-generic from-alien-function (type-spec))
382(define-type-generic cleanup-function (type-spec))
fc358945 383
4d1fea77 384(define-type-generic copy-to-alien-form (type-spec form))
385(define-type-generic copy-to-alien-function (type-spec))
386(define-type-generic copy-from-alien-form (type-spec form))
387(define-type-generic copy-from-alien-function (type-spec))
388(define-type-generic writer-function (type-spec))
389(define-type-generic reader-function (type-spec))
390(define-type-generic destroy-function (type-spec))
508d13a7 391
4d1fea77 392(define-type-generic unbound-value (type-spec)
393 "Returns a value which should be intepreted as unbound for slots with virtual allocation")
b6bf802c 394
fc358945 395
fb9bc912 396#+sbcl
397(eval-when (:compile-toplevel :load-toplevel :execute)
398 (defun sb-sizeof-bits (type)
399 (sb-alien-internals:alien-type-bits
400 (sb-alien-internals:parse-alien-type type nil)))
401
402 (defun sb-sizeof (type)
403 (/ (sb-sizeof-bits type) 8)))
404
405
7bde5a67 406;; Sizes of fundamental C types in bytes (8 bits)
fb9bc912 407(defconstant +size-of-short+
408 #+sbcl (sb-sizeof 'sb-alien:short)
409 #-sbcl 2)
410(defconstant +size-of-int+
411 #+sbcl (sb-sizeof 'sb-alien:int)
412 #-sbcl 4)
413(defconstant +size-of-long+
414 #+sbcl (sb-sizeof 'sb-alien:long)
415 #-sbcl 4)
416(defconstant +size-of-pointer+
417 #+sbcl (sb-sizeof 'sb-alien:system-area-pointer)
418 #-sbcl 4)
419(defconstant +size-of-float+
420 #+sbcl (sb-sizeof 'sb-alien:float)
421 #-sbcl 4)
422(defconstant +size-of-double+
423 #+sbcl (sb-sizeof 'sb-alien:double)
424 #-sbcl 8)
425
7bde5a67 426
427;; Sizes of fundamental C types in bits
428(defconstant +bits-of-byte+ 8)
fb9bc912 429(defconstant +bits-of-short+
430 #+sbcl (sb-sizeof-bits 'sb-alien:short)
431 #-sbcl 16)
432(defconstant +bits-of-int+
433 #+sbcl (sb-sizeof-bits 'sb-alien:int)
434 #-sbcl 32)
435(defconstant +bits-of-long+
436 #+sbcl (sb-sizeof-bits 'sb-alien:long)
437 #-sbcl 32)
7bde5a67 438
439
6baf860c 440(deftype int () '(signed-byte #.+bits-of-int+))
441(deftype unsigned-int () '(unsigned-byte #.+bits-of-int+))
442(deftype long () '(signed-byte #.+bits-of-long+))
443(deftype unsigned-long () '(unsigned-byte #.+bits-of-long+))
444(deftype short () '(signed-byte #.+bits-of-short+))
445(deftype unsigned-short () '(unsigned-byte #.+bits-of-short+))
446(deftype signed (&optional (size '*)) `(signed-byte ,size))
447(deftype unsigned (&optional (size '*)) `(unsigned-byte ,size))
448(deftype char () 'base-char)
449(deftype pointer () 'system-area-pointer)
4d1fea77 450(deftype boolean (&optional (size '*)) (declare (ignore size)) t)
451(deftype copy-of (type) type)
fc358945 452
4d1fea77 453(define-type-method alien-type ((type t))
454 (error "No alien type corresponding to the type specifier ~A" type))
fc358945 455
4d1fea77 456(define-type-method to-alien-form ((type t) form)
457 (declare (ignore form))
458 (error "Not a valid type specifier for arguments: ~A" type))
fc358945 459
4d1fea77 460(define-type-method to-alien-function ((type t))
461 (error "Not a valid type specifier for arguments: ~A" type))
fc358945 462
4d1fea77 463(define-type-method from-alien-form ((type t) form)
464 (declare (ignore form))
465 (error "Not a valid type specifier for return values: ~A" type))
fc358945 466
4d1fea77 467(define-type-method from-alien-function ((type t))
468 (error "Not a valid type specifier for return values: ~A" type))
6baf860c 469
4d1fea77 470(define-type-method cleanup-form ((type t) form)
471 (declare (ignore form type))
6baf860c 472 nil)
fc358945 473
4d1fea77 474(define-type-method cleanup-function ((type t))
475 (declare (ignore type))
6baf860c 476 #'identity)
477
4d1fea77 478(define-type-method callback-from-alien-form ((type t) form)
479 (copy-from-alien-form type form))
ae17423c 480
4d1fea77 481(define-type-method callback-cleanup-form ((type t) form)
482 (declare (ignore form type))
ae17423c 483 nil)
484
4d1fea77 485(define-type-method destroy-function ((type t))
486 (declare (ignore type))
4c795125 487 #'(lambda (location &optional offset)
6baf860c 488 (declare (ignore location offset))))
489
4d1fea77 490(define-type-method copy-to-alien-form ((type t) form)
491 (to-alien-form type form))
492
493(define-type-method copy-to-alien-function ((type t))
494 (to-alien-function type))
508d13a7 495
4d1fea77 496(define-type-method copy-from-alien-form ((type t) form)
497 (from-alien-form type form))
508d13a7 498
4d1fea77 499(define-type-method copy-from-alien-function ((type t))
500 (from-alien-function type))
508d13a7 501
508d13a7 502
4d1fea77 503(define-type-method to-alien-form ((type real) form)
6baf860c 504 (declare (ignore type))
4d1fea77 505 form)
506
507(define-type-method to-alien-function ((type real))
508 (declare (ignore type))
509 #'identity)
510
511(define-type-method from-alien-form ((type real) form)
512 (declare (ignore type))
513 form)
514
515(define-type-method from-alien-function ((type real))
516 (declare (ignore type))
517 #'identity)
518
519
520(define-type-method alien-type ((type integer))
521 (declare (ignore type))
522 (alien-type 'signed-byte))
523
524(define-type-method size-of ((type integer))
525 (declare (ignore type))
526 (size-of 'signed-byte))
527
528(define-type-method writer-function ((type integer))
529 (declare (ignore type))
530 (writer-function 'signed-byte))
531
532(define-type-method reader-function ((type integer))
533 (declare (ignore type))
534 (reader-function 'signed-byte))
535
536
537(define-type-method alien-type ((type signed-byte))
538 (destructuring-bind (&optional (size '*))
539 (rest (mklist (type-expand-to 'signed-byte type)))
6baf860c 540 (ecase size
3d36c5d6 541 (#.+bits-of-byte+ #+cmu'(alien:signed 8) #+sbcl'(sb-alien:signed 8))
542 (#.+bits-of-short+ #+cmu 'c-call:short #+sbcl 'sb-alien:short)
543 ((* #.+bits-of-int+) #+cmu 'c-call:int #+sbcl 'sb-alien:int)
544 (#.+bits-of-long+ #+cmu 'c-call:long #+sbcl 'sb-alien:long))))
6baf860c 545
4d1fea77 546(define-type-method size-of ((type signed-byte))
547 (destructuring-bind (&optional (size '*))
548 (rest (mklist (type-expand-to 'signed-byte type)))
6baf860c 549 (ecase size
550 (#.+bits-of-byte+ 1)
551 (#.+bits-of-short+ +size-of-short+)
552 ((* #.+bits-of-int+) +size-of-int+)
553 (#.+bits-of-long+ +size-of-long+))))
554
4d1fea77 555(define-type-method writer-function ((type signed-byte))
556 (destructuring-bind (&optional (size '*))
557 (rest (mklist (type-expand-to 'signed-byte type)))
6baf860c 558 (let ((size (if (eq size '*) +bits-of-int+ size)))
559 (ecase size
560 (8 #'(lambda (value location &optional (offset 0))
561 (setf (signed-sap-ref-8 location offset) value)))
562 (16 #'(lambda (value location &optional (offset 0))
563 (setf (signed-sap-ref-16 location offset) value)))
564 (32 #'(lambda (value location &optional (offset 0))
565 (setf (signed-sap-ref-32 location offset) value)))
566 (64 #'(lambda (value location &optional (offset 0))
567 (setf (signed-sap-ref-64 location offset) value)))))))
568
4d1fea77 569(define-type-method reader-function ((type signed-byte))
570 (destructuring-bind (&optional (size '*))
571 (rest (mklist (type-expand-to 'signed-byte type)))
6baf860c 572 (let ((size (if (eq size '*) +bits-of-int+ size)))
573 (ecase size
0739b019 574 (8 #'(lambda (sap &optional (offset 0) weak-p)
575 (declare (ignore weak-p))
6baf860c 576 (signed-sap-ref-8 sap offset)))
0739b019 577 (16 #'(lambda (sap &optional (offset 0) weak-p)
578 (declare (ignore weak-p))
6baf860c 579 (signed-sap-ref-16 sap offset)))
0739b019 580 (32 #'(lambda (sap &optional (offset 0) weak-p)
581 (declare (ignore weak-p))
6baf860c 582 (signed-sap-ref-32 sap offset)))
0739b019 583 (64 #'(lambda (sap &optional (offset 0) weak-p)
584 (declare (ignore weak-p))
6baf860c 585 (signed-sap-ref-64 sap offset)))))))
586
4d1fea77 587
588(define-type-method alien-type ((type unsigned-byte))
589 (destructuring-bind (&optional (size '*))
590 (rest (mklist (type-expand-to 'unsigned-byte type)))
6baf860c 591 (ecase size
3d36c5d6 592 (#.+bits-of-byte+ #+cmu'(alien:unsigned 8) #+sbcl'(sb-alien:unsigned 8))
593 (#.+bits-of-short+ #+cmu 'c-call:unsigned-short
594 #+sbcl 'sb-alien:unsigned-short)
595 ((* #.+bits-of-int+) #+cmu 'c-call:unsigned-int
596 #+sbcl 'sb-alien:unsigned-int)
597 (#.+bits-of-long+ #+cmu 'c-call:unsigned-long
598 #+sbcl 'sb-alien:unsigned-long))))
6baf860c 599
6baf860c 600
4d1fea77 601(define-type-method size-of ((type unsigned-byte))
602 (destructuring-bind (&optional (size '*))
603 (rest (mklist (type-expand-to 'unsigned-byte type)))
604 (size-of `(signed ,size))))
605
606(define-type-method writer-function ((type unsigned-byte))
607 (destructuring-bind (&optional (size '*))
608 (rest (mklist (type-expand-to 'unsigned-byte type)))
6baf860c 609 (let ((size (if (eq size '*) +bits-of-int+ size)))
610 (ecase size
611 (8 #'(lambda (value location &optional (offset 0))
612 (setf (sap-ref-8 location offset) value)))
613 (16 #'(lambda (value location &optional (offset 0))
614 (setf (sap-ref-16 location offset) value)))
615 (32 #'(lambda (value location &optional (offset 0))
616 (setf (sap-ref-32 location offset) value)))
617 (64 #'(lambda (value location &optional (offset 0))
618 (setf (sap-ref-64 location offset) value)))))))
619
4d1fea77 620(define-type-method reader-function ((type unsigned-byte))
621 (destructuring-bind (&optional (size '*))
622 (rest (mklist (type-expand-to 'unsigned-byte type)))
6baf860c 623 (let ((size (if (eq size '*) +bits-of-int+ size)))
624 (ecase size
0739b019 625 (8 #'(lambda (sap &optional (offset 0) weak-p)
626 (declare (ignore weak-p))
6baf860c 627 (sap-ref-8 sap offset)))
0739b019 628 (16 #'(lambda (sap &optional (offset 0) weak-p)
629 (declare (ignore weak-p))
6baf860c 630 (sap-ref-16 sap offset)))
0739b019 631 (32 #'(lambda (sap &optional (offset 0) weak-p)
632 (declare (ignore weak-p))
6baf860c 633 (sap-ref-32 sap offset)))
0739b019 634 (64 #'(lambda (sap &optional (offset 0) weak-p)
635 (declare (ignore weak-p))
6baf860c 636 (sap-ref-64 sap offset)))))))
42c6b247 637
4d1fea77 638(define-type-method alien-type ((type single-float))
639 (declare (ignore type))
3d36c5d6 640 #+cmu 'alien:single-float #+sbcl 'sb-alien:single-float)
fc358945 641
4d1fea77 642(define-type-method size-of ((type single-float))
643 (declare (ignore type))
fc358945 644 +size-of-float+)
645
4d1fea77 646(define-type-method to-alien-form ((type single-float) form)
647 (declare (ignore type))
472e1aae 648 `(coerce ,form 'single-float))
649
4d1fea77 650(define-type-method to-alien-function ((type single-float))
651 (declare (ignore type))
472e1aae 652 #'(lambda (number)
653 (coerce number 'single-float)))
654
4d1fea77 655(define-type-method writer-function ((type single-float))
656 (declare (ignore type))
6baf860c 657 #'(lambda (value location &optional (offset 0))
7bde5a67 658 (setf (sap-ref-single location offset) (coerce value 'single-float))))
fc358945 659
4d1fea77 660(define-type-method reader-function ((type single-float))
661 (declare (ignore type))
0739b019 662 #'(lambda (sap &optional (offset 0) weak-p)
663 (declare (ignore weak-p))
6baf860c 664 (sap-ref-single sap offset)))
fc358945 665
666
4d1fea77 667(define-type-method alien-type ((type double-float))
668 (declare (ignore type))
3d36c5d6 669 #+cmu 'alien:double-float #+sbcl 'sb-alien:double-float)
fc358945 670
4d1fea77 671(define-type-method size-of ((type double-float))
672 (declare (ignore type))
5b50f177 673 +size-of-double+)
fc358945 674
4d1fea77 675(define-type-method to-alien-form ((type double-float) form)
676 (declare (ignore type))
472e1aae 677 `(coerce ,form 'double-float))
678
4d1fea77 679(define-type-method to-alien-function ((type double-float))
680 (declare (ignore type))
472e1aae 681 #'(lambda (number)
682 (coerce number 'double-float)))
683
4d1fea77 684(define-type-method writer-function ((type double-float))
685 (declare (ignore type))
6baf860c 686 #'(lambda (value location &optional (offset 0))
687 (setf (sap-ref-double location offset) (coerce value 'double-float))))
fc358945 688
4d1fea77 689(define-type-method reader-function ((type double-float))
690 (declare (ignore type))
0739b019 691 #'(lambda (sap &optional (offset 0) weak-p)
692 (declare (ignore weak-p))
6baf860c 693 (sap-ref-double sap offset)))
fc358945 694
695
4d1fea77 696(define-type-method alien-type ((type base-char))
697 (declare (ignore type))
3d36c5d6 698 #+cmu 'c-call:char #+sbcl 'sb-alien:char)
fc358945 699
4d1fea77 700(define-type-method size-of ((type base-char))
701 (declare (ignore type))
fc358945 702 1)
703
4d1fea77 704(define-type-method to-alien-form ((type base-char) form)
705 (declare (ignore type))
706 form)
707
708(define-type-method to-alien-function ((type base-char))
709 (declare (ignore type))
710 #'identity)
711
712(define-type-method from-alien-form ((type base-char) form)
713 (declare (ignore type))
714 form)
715
716(define-type-method from-alien-function ((type base-char))
717 (declare (ignore type))
718 #'identity)
719
720(define-type-method writer-function ((type base-char))
721 (declare (ignore type))
6baf860c 722 #'(lambda (char location &optional (offset 0))
723 (setf (sap-ref-8 location offset) (char-code char))))
fc358945 724
4d1fea77 725(define-type-method reader-function ((type base-char))
726 (declare (ignore type))
0739b019 727 #'(lambda (location &optional (offset 0) weak-p)
728 (declare (ignore weak-p))
6baf860c 729 (code-char (sap-ref-8 location offset))))
fc358945 730
731
4d1fea77 732(define-type-method alien-type ((type string))
733 (declare (ignore type))
6baf860c 734 (alien-type 'pointer))
fc358945 735
4d1fea77 736(define-type-method size-of ((type string))
737 (declare (ignore type))
6baf860c 738 (size-of 'pointer))
fc358945 739
4d1fea77 740(define-type-method to-alien-form ((type string) string)
741 (declare (ignore type))
fc358945 742 `(let ((string ,string))
743 ;; Always copy strings to prevent seg fault due to GC
a9bb8f02 744 #+cmu
fc358945 745 (copy-memory
3d36c5d6 746 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 747 (1+ (length string)))
748 #+sbcl
749 (let ((utf8 (%deport-utf8-string string)))
750 (copy-memory (vector-sap utf8) (length utf8)))))
fc358945 751
4d1fea77 752(define-type-method to-alien-function ((type string))
753 (declare (ignore type))
6baf860c 754 #'(lambda (string)
a9bb8f02 755 #+cmu
6baf860c 756 (copy-memory
3d36c5d6 757 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 758 (1+ (length string)))
759 #+sbcl
760 (let ((utf8 (%deport-utf8-string string)))
761 (copy-memory (vector-sap utf8) (length utf8)))))
6baf860c 762
4d1fea77 763(define-type-method from-alien-form ((type string) string)
764 (declare (ignore type))
6baf860c 765 `(let ((string ,string))
766 (unless (null-pointer-p string)
508d13a7 767 (prog1
a9bb8f02 768 #+cmu(%naturalize-c-string string)
769 #+sbcl(%naturalize-utf8-string string)
508d13a7 770 (deallocate-memory string)))))
fc358945 771
4d1fea77 772(define-type-method from-alien-function ((type string))
773 (declare (ignore type))
6baf860c 774 #'(lambda (string)
775 (unless (null-pointer-p string)
508d13a7 776 (prog1
a9bb8f02 777 #+cmu(%naturalize-c-string string)
778 #+sbcl(%naturalize-utf8-string string)
508d13a7 779 (deallocate-memory string)))))
fc358945 780
4d1fea77 781(define-type-method cleanup-form ((type string) string)
782 (declare (ignore type))
6baf860c 783 `(let ((string ,string))
784 (unless (null-pointer-p string)
785 (deallocate-memory string))))
786
4d1fea77 787(define-type-method cleanup-function ((type string))
788 (declare (ignore type))
6baf860c 789 #'(lambda (string)
790 (unless (null-pointer-p string)
791 (deallocate-memory string))))
792
4d1fea77 793(define-type-method copy-from-alien-form ((type string) string)
794 (declare (ignore type))
508d13a7 795 `(let ((string ,string))
796 (unless (null-pointer-p string)
a9bb8f02 797 #+cmu(%naturalize-c-string string)
798 #+sbcl(%naturalize-utf8-string string))))
508d13a7 799
4d1fea77 800(define-type-method copy-from-alien-function ((type string))
801 (declare (ignore type))
508d13a7 802 #'(lambda (string)
803 (unless (null-pointer-p string)
a9bb8f02 804 #+cmu(%naturalize-c-string string)
805 #+sbcl(%naturalize-utf8-string string))))
508d13a7 806
4d1fea77 807(define-type-method writer-function ((type string))
808 (declare (ignore type))
6baf860c 809 #'(lambda (string location &optional (offset 0))
810 (assert (null-pointer-p (sap-ref-sap location offset)))
811 (setf (sap-ref-sap location offset)
a9bb8f02 812 #+cmu
6baf860c 813 (copy-memory
3d36c5d6 814 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 815 (1+ (length string)))
816 #+sbcl
817 (let ((utf8 (%deport-utf8-string string)))
818 (copy-memory (vector-sap utf8) (length utf8))))))
6baf860c 819
4d1fea77 820(define-type-method reader-function ((type string))
821 (declare (ignore type))
0739b019 822 #'(lambda (location &optional (offset 0) weak-p)
823 (declare (ignore weak-p))
6baf860c 824 (unless (null-pointer-p (sap-ref-sap location offset))
a9bb8f02 825 #+cmu(%naturalize-c-string (sap-ref-sap location offset))
826 #+sbcl(%naturalize-utf8-string (sap-ref-sap location offset)))))
6baf860c 827
4d1fea77 828(define-type-method destroy-function ((type string))
829 (declare (ignore type))
6baf860c 830 #'(lambda (location &optional (offset 0))
831 (unless (null-pointer-p (sap-ref-sap location offset))
832 (deallocate-memory (sap-ref-sap location offset))
833 (setf (sap-ref-sap location offset) (make-pointer 0)))))
834
4d1fea77 835(define-type-method unbound-value ((type string))
836 (declare (ignore type))
837 nil)
6baf860c 838
a9bb8f02 839
4d1fea77 840(define-type-method alien-type ((type pathname))
841 (declare (ignore type))
6baf860c 842 (alien-type 'string))
843
4d1fea77 844(define-type-method size-of ((type pathname))
845 (declare (ignore type))
6baf860c 846 (size-of 'string))
fc358945 847
4d1fea77 848(define-type-method to-alien-form ((type pathname) path)
849 (declare (ignore type))
850 (to-alien-form 'string `(namestring (translate-logical-pathname ,path))))
6baf860c 851
4d1fea77 852(define-type-method to-alien-function ((type pathname))
853 (declare (ignore type))
6baf860c 854 (let ((string-function (to-alien-function 'string)))
855 #'(lambda (path)
856 (funcall string-function (namestring path)))))
857
4d1fea77 858(define-type-method from-alien-form ((type pathname) string)
859 (declare (ignore type))
860 `(parse-namestring ,(from-alien-form 'string string)))
6baf860c 861
4d1fea77 862(define-type-method from-alien-function ((type pathname))
863 (declare (ignore type))
6baf860c 864 (let ((string-function (from-alien-function 'string)))
865 #'(lambda (string)
866 (parse-namestring (funcall string-function string)))))
867
4d1fea77 868(define-type-method cleanup-form ((type pathnanme) string)
869 (declare (ignore type))
870 (cleanup-form 'string string))
6baf860c 871
4d1fea77 872(define-type-method cleanup-function ((type pathnanme))
873 (declare (ignore type))
6baf860c 874 (cleanup-function 'string))
875
4d1fea77 876(define-type-method writer-function ((type pathname))
877 (declare (ignore type))
6baf860c 878 (let ((string-writer (writer-function 'string)))
879 #'(lambda (path location &optional (offset 0))
880 (funcall string-writer (namestring path) location offset))))
881
4d1fea77 882(define-type-method reader-function ((type pathname))
883 (declare (ignore type))
6baf860c 884 (let ((string-reader (reader-function 'string)))
0739b019 885 #'(lambda (location &optional (offset 0) weak-p)
886 (declare (ignore weak-p))
6baf860c 887 (let ((string (funcall string-reader location offset)))
888 (when string
889 (parse-namestring string))))))
890
4d1fea77 891(define-type-method destroy-function ((type pathname))
892 (declare (ignore type))
6baf860c 893 (destroy-function 'string))
894
4d1fea77 895(define-type-method unbound-value ((type pathname))
896 (declare (ignore type))
b6bf802c 897 (unbound-value 'string))
898
6baf860c 899
4d1fea77 900(define-type-method alien-type ((type boolean))
901 (destructuring-bind (&optional (size '*))
902 (rest (mklist (type-expand-to 'boolean type)))
903 (alien-type `(signed-byte ,size))))
6baf860c 904
4d1fea77 905(define-type-method size-of ((type boolean))
906 (destructuring-bind (&optional (size '*))
907 (rest (mklist (type-expand-to 'boolean type)))
908 (size-of `(signed-byte ,size))))
6baf860c 909
4d1fea77 910(define-type-method to-alien-form ((type boolean) boolean)
911 (declare (ignore type))
fc358945 912 `(if ,boolean 1 0))
913
4d1fea77 914(define-type-method to-alien-function ((type boolean))
915 (declare (ignore type))
6baf860c 916 #'(lambda (boolean)
917 (if boolean 1 0)))
918
4d1fea77 919(define-type-method from-alien-form ((type boolean) boolean)
920 (declare (ignore type))
6baf860c 921 `(not (zerop ,boolean)))
922
4d1fea77 923(define-type-method from-alien-function ((type boolean))
924 (declare (ignore type))
6baf860c 925 #'(lambda (boolean)
926 (not (zerop boolean))))
927
4d1fea77 928(define-type-method writer-function ((type boolean))
929 (destructuring-bind (&optional (size '*))
930 (rest (mklist (type-expand-to 'boolean type)))
931 (let ((writer (writer-function `(signed-byte ,size))))
932 #'(lambda (boolean location &optional (offset 0))
933 (funcall writer (if boolean 1 0) location offset)))))
934
935(define-type-method reader-function ((type boolean))
936 (destructuring-bind (&optional (size '*))
937 (rest (mklist (type-expand-to 'boolean type)))
938 (let ((reader (reader-function `(signed-byte ,size))))
939 #'(lambda (location &optional (offset 0) weak-p)
940 (declare (ignore weak-p))
941 (not (zerop (funcall reader location offset)))))))
942
943
944(define-type-method alien-type ((type or))
945 (let* ((expanded-type (type-expand-to 'or type))
946 (alien-type (alien-type (second expanded-type))))
6baf860c 947 (unless (every #'(lambda (type)
948 (eq alien-type (alien-type type)))
4d1fea77 949 (cddr expanded-type))
950 (error "No common alien type specifier for union type: ~A" type))
fc358945 951 alien-type))
952
4d1fea77 953(define-type-method size-of ((type or))
954 (size-of (second (type-expand-to 'or type))))
6baf860c 955
4d1fea77 956(define-type-method to-alien-form ((type or) form)
6baf860c 957 `(let ((value ,form))
4d1fea77 958 (etypecase value
959 ,@(mapcar
960 #'(lambda (type)
961 `(,type ,(to-alien-form type 'value)))
962 (rest (type-expand-to 'or type))))))
963
964(define-type-method to-alien-function ((type or))
965 (let* ((expanded-type (type-expand-to 'or type))
966 (functions (mapcar #'to-alien-function (rest expanded-type))))
6baf860c 967 #'(lambda (value)
968 (loop
969 for function in functions
4d1fea77 970 for alt-type in (rest expanded-type)
971 when (typep value alt-type)
6baf860c 972 do (return (funcall function value))
4d1fea77 973 finally (error "~S is not of type ~A" value type)))))
974
6baf860c 975
4d1fea77 976(define-type-method alien-type ((type pointer))
977 (declare (ignore type))
fc358945 978 'system-area-pointer)
979
4d1fea77 980(define-type-method size-of ((type pointer))
981 (declare (ignore type))
6baf860c 982 +size-of-pointer+)
fc358945 983
4d1fea77 984(define-type-method to-alien-form ((type pointer) form)
985 (declare (ignore type))
986 form)
987
988(define-type-method to-alien-function ((type pointer))
989 (declare (ignore type))
990 #'identity)
991
992(define-type-method from-alien-form ((type pointer) form)
993 (declare (ignore type))
994 form)
995
996(define-type-method from-alien-function ((type pointer))
997 (declare (ignore type))
998 #'identity)
999
1000(define-type-method writer-function ((type pointer))
1001 (declare (ignore type))
6baf860c 1002 #'(lambda (sap location &optional (offset 0))
1003 (setf (sap-ref-sap location offset) sap)))
fc358945 1004
4d1fea77 1005(define-type-method reader-function ((type pointer))
1006 (declare (ignore type))
0739b019 1007 #'(lambda (location &optional (offset 0) weak-p)
1008 (declare (ignore weak-p))
6baf860c 1009 (sap-ref-sap location offset)))
fc358945 1010
1011
4d1fea77 1012(define-type-method alien-type ((type null))
1013 (declare (ignore type))
6baf860c 1014 (alien-type 'pointer))
fc358945 1015
4d1fea77 1016(define-type-method size-of ((type null))
1017 (declare (ignore type))
6baf860c 1018 (size-of 'pointer))
1019
4d1fea77 1020(define-type-method to-alien-form ((type null) null)
1021 (declare (ignore null type))
fc358945 1022 `(make-pointer 0))
1023
4d1fea77 1024(define-type-method to-alien-function ((type null))
1025 (declare (ignore type))
6baf860c 1026 #'(lambda (null)
1027 (declare (ignore null))
1028 (make-pointer 0)))
fc358945 1029
fc358945 1030
4d1fea77 1031(define-type-method alien-type ((type nil))
1032 (declare (ignore type))
3d36c5d6 1033 'void)
6baf860c 1034
4d1fea77 1035(define-type-method from-alien-function ((type nil))
1036 (declare (ignore type))
6baf860c 1037 #'(lambda (value)
1038 (declare (ignore value))
1039 (values)))
508d13a7 1040
4d1fea77 1041(define-type-method to-alien-form ((type nil) form)
508d13a7 1042 (declare (ignore type))
4d1fea77 1043 form)
508d13a7 1044
508d13a7 1045
4d1fea77 1046(define-type-method to-alien-form ((type copy-of) form)
1047 (copy-to-alien-form (second (type-expand-to 'copy-of type)) form))
508d13a7 1048
4d1fea77 1049(define-type-method to-alien-function ((type copy-of))
1050 (copy-to-alien-function (second (type-expand-to 'copy-of type))))
508d13a7 1051
4d1fea77 1052(define-type-method from-alien-form ((type copy-of) form)
1053 (copy-from-alien-form (second (type-expand-to 'copy-of type)) form))
508d13a7 1054
4d1fea77 1055(define-type-method from-alien-function ((type copy-of))
1056 (copy-from-alien-function (second (type-expand-to 'copy-of type))))
508d13a7 1057
4c795125 1058
4d1fea77 1059(define-type-method alien-type ((type callback))
4c795125 1060 (declare (ignore type))
ff8fa451 1061 (alien-type 'pointer))
1062
4d1fea77 1063(define-type-method to-alien-form ((type callback) callback)
1064 (declare (ignore type ))
ae17423c 1065 `(callback-address ,callback))