Custom types are now re-registered when a saved image is loaded
[clg] / glib / ffi.lisp
CommitLineData
112ac1d3 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 1999-2005 Espen S. Johnsen <espen@users.sf.net>
310da1d5 3;;
112ac1d3 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:
310da1d5 11;;
112ac1d3 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
310da1d5 14;;
112ac1d3 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
1dc849d7 23;; $Id: ffi.lisp,v 1.30 2006-03-03 20:31:24 espen Exp $
310da1d5 24
25(in-package "GLIB")
26
310da1d5 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)))
a7d19b2a 34 (setq *package-prefix* (delete package *package-prefix* :key #'car))
310da1d5 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)
1ff84b06 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*)))
310da1d5 68 (if (or (not prefix) (string= prefix ""))
1ff84b06 69 stripped-name
70 (format nil "~A_~A" prefix stripped-name))))
310da1d5 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
9adccb27 91(defmacro defbinding (name lambda-list return-type &rest docs/args)
310da1d5 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
3840beb2 105 (unless (member style '(:in :out :in-out :return))
310da1d5 106 (error "Bogus argument style ~S in ~S." style doc/arg))
107 (when (and
108 (not supplied-lambda-list)
3840beb2 109 (namep expr) (member style '(:in :in-out :return)))
310da1d5 110 (push expr lambda-list))
7a6c048d 111 (push (list (cond
112 ((and (namep expr) (eq style :out)) expr)
113 ((namep expr) (make-symbol (string expr)))
114 ((gensym)))
75689fea 115 expr type style) args)))))
310da1d5 116
117 (%defbinding
118 c-name lisp-name (or supplied-lambda-list (nreverse lambda-list))
9adccb27 119 return-type (reverse docs) (reverse args)))))
310da1d5 120
73572c12 121#+(or cmu sbcl)
9adccb27 122(defun %defbinding (foreign-name lisp-name lambda-list return-type docs args)
73572c12 123 (collect ((alien-types) (alien-bindings) (alien-parameters)
124 (return-values) (cleanup-forms))
310da1d5 125 (dolist (arg args)
9adccb27 126 (destructuring-bind (var expr type style) arg
127 (let ((declaration (alien-type type))
75689fea 128 (cleanup (cleanup-form type var)))
9adccb27 129
310da1d5 130 (cond
3840beb2 131 ((member style '(:out :in-out))
132 (alien-types `(* ,declaration))
133 (alien-parameters `(addr ,var))
134 (alien-bindings
135 `(,var ,declaration
fefc2058 136 ,@(cond
75689fea 137 ((eq style :in-out) (list (to-alien-form type expr)))
fefc2058 138 ((eq declaration 'system-area-pointer)
139 (list '(make-pointer 0))))))
75689fea 140 (return-values (from-alien-form type var)))
3840beb2 141 ((eq style :return)
142 (alien-types declaration)
143 (alien-bindings
75689fea 144 `(,var ,declaration ,(to-alien-form type expr)))
3840beb2 145 (alien-parameters var)
75689fea 146 (return-values (from-alien-form type var)))
3840beb2 147 (cleanup
148 (alien-types declaration)
149 (alien-bindings
75689fea 150 `(,var ,declaration ,(to-alien-form type expr)))
3840beb2 151 (alien-parameters var)
152 (cleanup-forms cleanup))
153 (t
154 (alien-types declaration)
75689fea 155 (alien-parameters (to-alien-form type expr)))))))
310da1d5 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
73572c12 161 #+cmu(declare (optimize (inhibit-warnings 3)))
162 #+sbcl(declare (muffle-conditions compiler-note))
310da1d5 163 (with-alien ((,alien-name
164 (function
9adccb27 165 ,(alien-type return-type)
310da1d5 166 ,@(alien-types))
167 :extern ,foreign-name)
168 ,@(alien-bindings))
9adccb27 169 ,(if return-type
170 `(values
171 (unwind-protect
75689fea 172 ,(from-alien-form return-type alien-funcall)
9adccb27 173 ,@(cleanup-forms))
3840beb2 174 ,@(return-values))
310da1d5 175 `(progn
9adccb27 176 (unwind-protect
177 ,alien-funcall
178 ,@(cleanup-forms))
3840beb2 179 (values ,@(return-values)))))))))
310da1d5 180
181
9adccb27 182;;; Creates bindings at runtime
310da1d5 183(defun mkbinding (name return-type &rest arg-types)
73572c12 184 #+cmu(declare (optimize (inhibit-warnings 3)))
185 #+sbcl(declare (muffle-conditions compiler-note))
9adccb27 186 (let* ((ftype
187 `(function ,@(mapcar #'alien-type (cons return-type arg-types))))
310da1d5 188 (alien
73572c12 189 (%heap-alien
190 (make-heap-alien-info
191 :type (parse-alien-type ftype #+sbcl nil)
177abaa0 192 :sap-form (let ((address (foreign-symbol-address name)))
193 (etypecase address
194 (integer (int-sap address))
195 (system-area-pointer address))))))
9adccb27 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
310da1d5 200 #'(lambda (&rest args)
201 (map-into args #'funcall translate-arguments args)
202 (prog1
9adccb27 203 (funcall translate-return-value
73572c12 204 (apply #'alien-funcall alien args))
310da1d5 205 (mapc #'funcall cleanup-arguments args)))))
206
8755b1a5 207
73572c12 208
586328b4 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)))
75689fea 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
586328b4 244 for (name type) in args
75689fea 245 do (callback-cleanup-form type name))))))))))
586328b4 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))
8755b1a5 251
7e29d6b1 252#+sbcl
586328b4 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
310da1d5 268
75689fea 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
c96779a5 351 (unless (get ',name 'type-methods)
352 (setf (get ',name 'type-methods) (make-hash-table))
353 (setf (get ',name 'built-in-type-hierarchy) ()))
75689fea 354 (defun ,name ,lambda-list
355 ,documentation
356 (funcall
357 (find-applicable-type-method ',name ,(first lambda-list))
358 ,@lambda-list)))))
359
360
361(defmacro define-type-method (name lambda-list &body body)
362 (let ((specifier (cadar lambda-list))
363 (args (cons (caar lambda-list) (rest lambda-list))))
364 `(progn
365 (add-type-method ',name ',specifier #'(lambda ,args ,@body))
366 ',name)))
367
368
369
370;;;; Definitons and translations of fundamental types
371
372(define-type-generic alien-type (type-spec))
373(define-type-generic size-of (type-spec))
374(define-type-generic to-alien-form (type-spec form))
375(define-type-generic from-alien-form (type-spec form))
376(define-type-generic cleanup-form (type-spec form)
9adccb27 377 "Creates a form to clean up after the alien call has finished.")
75689fea 378(define-type-generic callback-from-alien-form (type-spec form))
379(define-type-generic callback-cleanup-form (type-spec form))
310da1d5 380
75689fea 381(define-type-generic to-alien-function (type-spec))
382(define-type-generic from-alien-function (type-spec))
383(define-type-generic cleanup-function (type-spec))
310da1d5 384
75689fea 385(define-type-generic copy-to-alien-form (type-spec form))
386(define-type-generic copy-to-alien-function (type-spec))
387(define-type-generic copy-from-alien-form (type-spec form))
388(define-type-generic copy-from-alien-function (type-spec))
389(define-type-generic writer-function (type-spec))
390(define-type-generic reader-function (type-spec))
391(define-type-generic destroy-function (type-spec))
9ca5565a 392
75689fea 393(define-type-generic unbound-value (type-spec)
394 "Returns a value which should be intepreted as unbound for slots with virtual allocation")
12b7df04 395
310da1d5 396
42e68ad2 397#+sbcl
398(eval-when (:compile-toplevel :load-toplevel :execute)
399 (defun sb-sizeof-bits (type)
400 (sb-alien-internals:alien-type-bits
401 (sb-alien-internals:parse-alien-type type nil)))
402
403 (defun sb-sizeof (type)
404 (/ (sb-sizeof-bits type) 8)))
405
406
8755b1a5 407;; Sizes of fundamental C types in bytes (8 bits)
42e68ad2 408(defconstant +size-of-short+
409 #+sbcl (sb-sizeof 'sb-alien:short)
410 #-sbcl 2)
411(defconstant +size-of-int+
412 #+sbcl (sb-sizeof 'sb-alien:int)
413 #-sbcl 4)
414(defconstant +size-of-long+
415 #+sbcl (sb-sizeof 'sb-alien:long)
416 #-sbcl 4)
417(defconstant +size-of-pointer+
418 #+sbcl (sb-sizeof 'sb-alien:system-area-pointer)
419 #-sbcl 4)
420(defconstant +size-of-float+
421 #+sbcl (sb-sizeof 'sb-alien:float)
422 #-sbcl 4)
423(defconstant +size-of-double+
424 #+sbcl (sb-sizeof 'sb-alien:double)
425 #-sbcl 8)
426
8755b1a5 427
428;; Sizes of fundamental C types in bits
429(defconstant +bits-of-byte+ 8)
42e68ad2 430(defconstant +bits-of-short+
431 #+sbcl (sb-sizeof-bits 'sb-alien:short)
432 #-sbcl 16)
433(defconstant +bits-of-int+
434 #+sbcl (sb-sizeof-bits 'sb-alien:int)
435 #-sbcl 32)
436(defconstant +bits-of-long+
437 #+sbcl (sb-sizeof-bits 'sb-alien:long)
438 #-sbcl 32)
8755b1a5 439
440
9adccb27 441(deftype int () '(signed-byte #.+bits-of-int+))
442(deftype unsigned-int () '(unsigned-byte #.+bits-of-int+))
443(deftype long () '(signed-byte #.+bits-of-long+))
444(deftype unsigned-long () '(unsigned-byte #.+bits-of-long+))
445(deftype short () '(signed-byte #.+bits-of-short+))
446(deftype unsigned-short () '(unsigned-byte #.+bits-of-short+))
447(deftype signed (&optional (size '*)) `(signed-byte ,size))
448(deftype unsigned (&optional (size '*)) `(unsigned-byte ,size))
449(deftype char () 'base-char)
450(deftype pointer () 'system-area-pointer)
75689fea 451(deftype boolean (&optional (size '*)) (declare (ignore size)) t)
452(deftype copy-of (type) type)
310da1d5 453
75689fea 454(define-type-method alien-type ((type t))
455 (error "No alien type corresponding to the type specifier ~A" type))
310da1d5 456
75689fea 457(define-type-method to-alien-form ((type t) form)
458 (declare (ignore form))
459 (error "Not a valid type specifier for arguments: ~A" type))
310da1d5 460
75689fea 461(define-type-method to-alien-function ((type t))
462 (error "Not a valid type specifier for arguments: ~A" type))
310da1d5 463
75689fea 464(define-type-method from-alien-form ((type t) form)
465 (declare (ignore form))
466 (error "Not a valid type specifier for return values: ~A" type))
310da1d5 467
75689fea 468(define-type-method from-alien-function ((type t))
469 (error "Not a valid type specifier for return values: ~A" type))
9adccb27 470
75689fea 471(define-type-method cleanup-form ((type t) form)
472 (declare (ignore form type))
9adccb27 473 nil)
310da1d5 474
75689fea 475(define-type-method cleanup-function ((type t))
476 (declare (ignore type))
9adccb27 477 #'identity)
478
75689fea 479(define-type-method callback-from-alien-form ((type t) form)
480 (copy-from-alien-form type form))
586328b4 481
75689fea 482(define-type-method callback-cleanup-form ((type t) form)
483 (declare (ignore form type))
586328b4 484 nil)
485
75689fea 486(define-type-method destroy-function ((type t))
487 (declare (ignore type))
cdd375f3 488 #'(lambda (location &optional offset)
9adccb27 489 (declare (ignore location offset))))
490
75689fea 491(define-type-method copy-to-alien-form ((type t) form)
492 (to-alien-form type form))
493
494(define-type-method copy-to-alien-function ((type t))
495 (to-alien-function type))
9ca5565a 496
75689fea 497(define-type-method copy-from-alien-form ((type t) form)
498 (from-alien-form type form))
9ca5565a 499
75689fea 500(define-type-method copy-from-alien-function ((type t))
501 (from-alien-function type))
9ca5565a 502
9ca5565a 503
75689fea 504(define-type-method to-alien-form ((type real) form)
9adccb27 505 (declare (ignore type))
75689fea 506 form)
507
508(define-type-method to-alien-function ((type real))
509 (declare (ignore type))
510 #'identity)
511
512(define-type-method from-alien-form ((type real) form)
513 (declare (ignore type))
514 form)
515
516(define-type-method from-alien-function ((type real))
517 (declare (ignore type))
518 #'identity)
519
520
521(define-type-method alien-type ((type integer))
522 (declare (ignore type))
523 (alien-type 'signed-byte))
524
525(define-type-method size-of ((type integer))
526 (declare (ignore type))
527 (size-of 'signed-byte))
528
529(define-type-method writer-function ((type integer))
530 (declare (ignore type))
531 (writer-function 'signed-byte))
532
533(define-type-method reader-function ((type integer))
534 (declare (ignore type))
535 (reader-function 'signed-byte))
536
537
538(define-type-method alien-type ((type signed-byte))
539 (destructuring-bind (&optional (size '*))
540 (rest (mklist (type-expand-to 'signed-byte type)))
9adccb27 541 (ecase size
73572c12 542 (#.+bits-of-byte+ #+cmu'(alien:signed 8) #+sbcl'(sb-alien:signed 8))
543 (#.+bits-of-short+ #+cmu 'c-call:short #+sbcl 'sb-alien:short)
544 ((* #.+bits-of-int+) #+cmu 'c-call:int #+sbcl 'sb-alien:int)
545 (#.+bits-of-long+ #+cmu 'c-call:long #+sbcl 'sb-alien:long))))
9adccb27 546
75689fea 547(define-type-method size-of ((type signed-byte))
548 (destructuring-bind (&optional (size '*))
549 (rest (mklist (type-expand-to 'signed-byte type)))
9adccb27 550 (ecase size
551 (#.+bits-of-byte+ 1)
552 (#.+bits-of-short+ +size-of-short+)
553 ((* #.+bits-of-int+) +size-of-int+)
554 (#.+bits-of-long+ +size-of-long+))))
555
75689fea 556(define-type-method writer-function ((type signed-byte))
557 (destructuring-bind (&optional (size '*))
558 (rest (mklist (type-expand-to 'signed-byte type)))
9adccb27 559 (let ((size (if (eq size '*) +bits-of-int+ size)))
560 (ecase size
561 (8 #'(lambda (value location &optional (offset 0))
562 (setf (signed-sap-ref-8 location offset) value)))
563 (16 #'(lambda (value location &optional (offset 0))
564 (setf (signed-sap-ref-16 location offset) value)))
565 (32 #'(lambda (value location &optional (offset 0))
566 (setf (signed-sap-ref-32 location offset) value)))
567 (64 #'(lambda (value location &optional (offset 0))
568 (setf (signed-sap-ref-64 location offset) value)))))))
569
75689fea 570(define-type-method reader-function ((type signed-byte))
571 (destructuring-bind (&optional (size '*))
572 (rest (mklist (type-expand-to 'signed-byte type)))
9adccb27 573 (let ((size (if (eq size '*) +bits-of-int+ size)))
574 (ecase size
3005806e 575 (8 #'(lambda (sap &optional (offset 0) weak-p)
576 (declare (ignore weak-p))
9adccb27 577 (signed-sap-ref-8 sap offset)))
3005806e 578 (16 #'(lambda (sap &optional (offset 0) weak-p)
579 (declare (ignore weak-p))
9adccb27 580 (signed-sap-ref-16 sap offset)))
3005806e 581 (32 #'(lambda (sap &optional (offset 0) weak-p)
582 (declare (ignore weak-p))
9adccb27 583 (signed-sap-ref-32 sap offset)))
3005806e 584 (64 #'(lambda (sap &optional (offset 0) weak-p)
585 (declare (ignore weak-p))
9adccb27 586 (signed-sap-ref-64 sap offset)))))))
587
75689fea 588
589(define-type-method alien-type ((type unsigned-byte))
590 (destructuring-bind (&optional (size '*))
591 (rest (mklist (type-expand-to 'unsigned-byte type)))
9adccb27 592 (ecase size
73572c12 593 (#.+bits-of-byte+ #+cmu'(alien:unsigned 8) #+sbcl'(sb-alien:unsigned 8))
594 (#.+bits-of-short+ #+cmu 'c-call:unsigned-short
595 #+sbcl 'sb-alien:unsigned-short)
596 ((* #.+bits-of-int+) #+cmu 'c-call:unsigned-int
597 #+sbcl 'sb-alien:unsigned-int)
598 (#.+bits-of-long+ #+cmu 'c-call:unsigned-long
599 #+sbcl 'sb-alien:unsigned-long))))
9adccb27 600
9adccb27 601
75689fea 602(define-type-method size-of ((type unsigned-byte))
603 (destructuring-bind (&optional (size '*))
604 (rest (mklist (type-expand-to 'unsigned-byte type)))
605 (size-of `(signed ,size))))
606
607(define-type-method writer-function ((type unsigned-byte))
608 (destructuring-bind (&optional (size '*))
609 (rest (mklist (type-expand-to 'unsigned-byte type)))
9adccb27 610 (let ((size (if (eq size '*) +bits-of-int+ size)))
611 (ecase size
612 (8 #'(lambda (value location &optional (offset 0))
613 (setf (sap-ref-8 location offset) value)))
614 (16 #'(lambda (value location &optional (offset 0))
615 (setf (sap-ref-16 location offset) value)))
616 (32 #'(lambda (value location &optional (offset 0))
617 (setf (sap-ref-32 location offset) value)))
618 (64 #'(lambda (value location &optional (offset 0))
619 (setf (sap-ref-64 location offset) value)))))))
620
75689fea 621(define-type-method reader-function ((type unsigned-byte))
622 (destructuring-bind (&optional (size '*))
623 (rest (mklist (type-expand-to 'unsigned-byte type)))
9adccb27 624 (let ((size (if (eq size '*) +bits-of-int+ size)))
625 (ecase size
3005806e 626 (8 #'(lambda (sap &optional (offset 0) weak-p)
627 (declare (ignore weak-p))
9adccb27 628 (sap-ref-8 sap offset)))
3005806e 629 (16 #'(lambda (sap &optional (offset 0) weak-p)
630 (declare (ignore weak-p))
9adccb27 631 (sap-ref-16 sap offset)))
3005806e 632 (32 #'(lambda (sap &optional (offset 0) weak-p)
633 (declare (ignore weak-p))
9adccb27 634 (sap-ref-32 sap offset)))
3005806e 635 (64 #'(lambda (sap &optional (offset 0) weak-p)
636 (declare (ignore weak-p))
9adccb27 637 (sap-ref-64 sap offset)))))))
78778e5a 638
75689fea 639(define-type-method alien-type ((type single-float))
640 (declare (ignore type))
73572c12 641 #+cmu 'alien:single-float #+sbcl 'sb-alien:single-float)
310da1d5 642
75689fea 643(define-type-method size-of ((type single-float))
644 (declare (ignore type))
310da1d5 645 +size-of-float+)
646
75689fea 647(define-type-method to-alien-form ((type single-float) form)
648 (declare (ignore type))
af6d8c9a 649 `(coerce ,form 'single-float))
650
75689fea 651(define-type-method to-alien-function ((type single-float))
652 (declare (ignore type))
af6d8c9a 653 #'(lambda (number)
654 (coerce number 'single-float)))
655
75689fea 656(define-type-method writer-function ((type single-float))
657 (declare (ignore type))
9adccb27 658 #'(lambda (value location &optional (offset 0))
8755b1a5 659 (setf (sap-ref-single location offset) (coerce value 'single-float))))
310da1d5 660
75689fea 661(define-type-method reader-function ((type single-float))
662 (declare (ignore type))
3005806e 663 #'(lambda (sap &optional (offset 0) weak-p)
664 (declare (ignore weak-p))
9adccb27 665 (sap-ref-single sap offset)))
310da1d5 666
667
75689fea 668(define-type-method alien-type ((type double-float))
669 (declare (ignore type))
73572c12 670 #+cmu 'alien:double-float #+sbcl 'sb-alien:double-float)
310da1d5 671
75689fea 672(define-type-method size-of ((type double-float))
673 (declare (ignore type))
3d285e35 674 +size-of-double+)
310da1d5 675
75689fea 676(define-type-method to-alien-form ((type double-float) form)
677 (declare (ignore type))
af6d8c9a 678 `(coerce ,form 'double-float))
679
75689fea 680(define-type-method to-alien-function ((type double-float))
681 (declare (ignore type))
af6d8c9a 682 #'(lambda (number)
683 (coerce number 'double-float)))
684
75689fea 685(define-type-method writer-function ((type double-float))
686 (declare (ignore type))
9adccb27 687 #'(lambda (value location &optional (offset 0))
688 (setf (sap-ref-double location offset) (coerce value 'double-float))))
310da1d5 689
75689fea 690(define-type-method reader-function ((type double-float))
691 (declare (ignore type))
3005806e 692 #'(lambda (sap &optional (offset 0) weak-p)
693 (declare (ignore weak-p))
9adccb27 694 (sap-ref-double sap offset)))
310da1d5 695
696
75689fea 697(define-type-method alien-type ((type base-char))
698 (declare (ignore type))
73572c12 699 #+cmu 'c-call:char #+sbcl 'sb-alien:char)
310da1d5 700
75689fea 701(define-type-method size-of ((type base-char))
702 (declare (ignore type))
310da1d5 703 1)
704
75689fea 705(define-type-method to-alien-form ((type base-char) form)
706 (declare (ignore type))
707 form)
708
709(define-type-method to-alien-function ((type base-char))
710 (declare (ignore type))
711 #'identity)
712
713(define-type-method from-alien-form ((type base-char) form)
714 (declare (ignore type))
715 form)
716
717(define-type-method from-alien-function ((type base-char))
718 (declare (ignore type))
719 #'identity)
720
721(define-type-method writer-function ((type base-char))
722 (declare (ignore type))
9adccb27 723 #'(lambda (char location &optional (offset 0))
724 (setf (sap-ref-8 location offset) (char-code char))))
310da1d5 725
75689fea 726(define-type-method reader-function ((type base-char))
727 (declare (ignore type))
3005806e 728 #'(lambda (location &optional (offset 0) weak-p)
729 (declare (ignore weak-p))
9adccb27 730 (code-char (sap-ref-8 location offset))))
310da1d5 731
732
75689fea 733(define-type-method alien-type ((type string))
734 (declare (ignore type))
9adccb27 735 (alien-type 'pointer))
310da1d5 736
75689fea 737(define-type-method size-of ((type string))
738 (declare (ignore type))
9adccb27 739 (size-of 'pointer))
310da1d5 740
75689fea 741(define-type-method to-alien-form ((type string) string)
742 (declare (ignore type))
310da1d5 743 `(let ((string ,string))
744 ;; Always copy strings to prevent seg fault due to GC
6896c0f3 745 #+cmu
310da1d5 746 (copy-memory
73572c12 747 (vector-sap (coerce string 'simple-base-string))
6896c0f3 748 (1+ (length string)))
749 #+sbcl
750 (let ((utf8 (%deport-utf8-string string)))
751 (copy-memory (vector-sap utf8) (length utf8)))))
310da1d5 752
75689fea 753(define-type-method to-alien-function ((type string))
754 (declare (ignore type))
9adccb27 755 #'(lambda (string)
6896c0f3 756 #+cmu
9adccb27 757 (copy-memory
73572c12 758 (vector-sap (coerce string 'simple-base-string))
6896c0f3 759 (1+ (length string)))
760 #+sbcl
761 (let ((utf8 (%deport-utf8-string string)))
762 (copy-memory (vector-sap utf8) (length utf8)))))
9adccb27 763
75689fea 764(define-type-method from-alien-form ((type string) string)
765 (declare (ignore type))
9adccb27 766 `(let ((string ,string))
767 (unless (null-pointer-p string)
9ca5565a 768 (prog1
6896c0f3 769 #+cmu(%naturalize-c-string string)
770 #+sbcl(%naturalize-utf8-string string)
9ca5565a 771 (deallocate-memory string)))))
310da1d5 772
75689fea 773(define-type-method from-alien-function ((type string))
774 (declare (ignore type))
9adccb27 775 #'(lambda (string)
776 (unless (null-pointer-p string)
9ca5565a 777 (prog1
6896c0f3 778 #+cmu(%naturalize-c-string string)
779 #+sbcl(%naturalize-utf8-string string)
9ca5565a 780 (deallocate-memory string)))))
310da1d5 781
75689fea 782(define-type-method cleanup-form ((type string) string)
783 (declare (ignore type))
9adccb27 784 `(let ((string ,string))
785 (unless (null-pointer-p string)
786 (deallocate-memory string))))
787
75689fea 788(define-type-method cleanup-function ((type string))
789 (declare (ignore type))
9adccb27 790 #'(lambda (string)
791 (unless (null-pointer-p string)
792 (deallocate-memory string))))
793
75689fea 794(define-type-method copy-from-alien-form ((type string) string)
795 (declare (ignore type))
9ca5565a 796 `(let ((string ,string))
797 (unless (null-pointer-p string)
6896c0f3 798 #+cmu(%naturalize-c-string string)
799 #+sbcl(%naturalize-utf8-string string))))
9ca5565a 800
75689fea 801(define-type-method copy-from-alien-function ((type string))
802 (declare (ignore type))
9ca5565a 803 #'(lambda (string)
804 (unless (null-pointer-p string)
6896c0f3 805 #+cmu(%naturalize-c-string string)
806 #+sbcl(%naturalize-utf8-string string))))
9ca5565a 807
75689fea 808(define-type-method writer-function ((type string))
809 (declare (ignore type))
9adccb27 810 #'(lambda (string location &optional (offset 0))
811 (assert (null-pointer-p (sap-ref-sap location offset)))
812 (setf (sap-ref-sap location offset)
6896c0f3 813 #+cmu
9adccb27 814 (copy-memory
73572c12 815 (vector-sap (coerce string 'simple-base-string))
6896c0f3 816 (1+ (length string)))
817 #+sbcl
818 (let ((utf8 (%deport-utf8-string string)))
819 (copy-memory (vector-sap utf8) (length utf8))))))
9adccb27 820
75689fea 821(define-type-method reader-function ((type string))
822 (declare (ignore type))
3005806e 823 #'(lambda (location &optional (offset 0) weak-p)
824 (declare (ignore weak-p))
9adccb27 825 (unless (null-pointer-p (sap-ref-sap location offset))
6896c0f3 826 #+cmu(%naturalize-c-string (sap-ref-sap location offset))
827 #+sbcl(%naturalize-utf8-string (sap-ref-sap location offset)))))
9adccb27 828
75689fea 829(define-type-method destroy-function ((type string))
830 (declare (ignore type))
9adccb27 831 #'(lambda (location &optional (offset 0))
832 (unless (null-pointer-p (sap-ref-sap location offset))
833 (deallocate-memory (sap-ref-sap location offset))
834 (setf (sap-ref-sap location offset) (make-pointer 0)))))
835
75689fea 836(define-type-method unbound-value ((type string))
837 (declare (ignore type))
838 nil)
9adccb27 839
6896c0f3 840
75689fea 841(define-type-method alien-type ((type pathname))
842 (declare (ignore type))
9adccb27 843 (alien-type 'string))
844
75689fea 845(define-type-method size-of ((type pathname))
846 (declare (ignore type))
9adccb27 847 (size-of 'string))
310da1d5 848
75689fea 849(define-type-method to-alien-form ((type pathname) path)
850 (declare (ignore type))
851 (to-alien-form 'string `(namestring (translate-logical-pathname ,path))))
9adccb27 852
75689fea 853(define-type-method to-alien-function ((type pathname))
854 (declare (ignore type))
9adccb27 855 (let ((string-function (to-alien-function 'string)))
856 #'(lambda (path)
857 (funcall string-function (namestring path)))))
858
75689fea 859(define-type-method from-alien-form ((type pathname) string)
860 (declare (ignore type))
861 `(parse-namestring ,(from-alien-form 'string string)))
9adccb27 862
75689fea 863(define-type-method from-alien-function ((type pathname))
864 (declare (ignore type))
9adccb27 865 (let ((string-function (from-alien-function 'string)))
866 #'(lambda (string)
867 (parse-namestring (funcall string-function string)))))
868
75689fea 869(define-type-method cleanup-form ((type pathnanme) string)
870 (declare (ignore type))
871 (cleanup-form 'string string))
9adccb27 872
75689fea 873(define-type-method cleanup-function ((type pathnanme))
874 (declare (ignore type))
9adccb27 875 (cleanup-function 'string))
876
75689fea 877(define-type-method writer-function ((type pathname))
878 (declare (ignore type))
9adccb27 879 (let ((string-writer (writer-function 'string)))
880 #'(lambda (path location &optional (offset 0))
881 (funcall string-writer (namestring path) location offset))))
882
75689fea 883(define-type-method reader-function ((type pathname))
884 (declare (ignore type))
9adccb27 885 (let ((string-reader (reader-function 'string)))
3005806e 886 #'(lambda (location &optional (offset 0) weak-p)
887 (declare (ignore weak-p))
9adccb27 888 (let ((string (funcall string-reader location offset)))
889 (when string
890 (parse-namestring string))))))
891
75689fea 892(define-type-method destroy-function ((type pathname))
893 (declare (ignore type))
9adccb27 894 (destroy-function 'string))
895
75689fea 896(define-type-method unbound-value ((type pathname))
897 (declare (ignore type))
12b7df04 898 (unbound-value 'string))
899
9adccb27 900
75689fea 901(define-type-method alien-type ((type boolean))
902 (destructuring-bind (&optional (size '*))
903 (rest (mklist (type-expand-to 'boolean type)))
904 (alien-type `(signed-byte ,size))))
9adccb27 905
75689fea 906(define-type-method size-of ((type boolean))
907 (destructuring-bind (&optional (size '*))
908 (rest (mklist (type-expand-to 'boolean type)))
909 (size-of `(signed-byte ,size))))
9adccb27 910
75689fea 911(define-type-method to-alien-form ((type boolean) boolean)
912 (declare (ignore type))
310da1d5 913 `(if ,boolean 1 0))
914
75689fea 915(define-type-method to-alien-function ((type boolean))
916 (declare (ignore type))
9adccb27 917 #'(lambda (boolean)
918 (if boolean 1 0)))
919
75689fea 920(define-type-method from-alien-form ((type boolean) boolean)
921 (declare (ignore type))
9adccb27 922 `(not (zerop ,boolean)))
923
75689fea 924(define-type-method from-alien-function ((type boolean))
925 (declare (ignore type))
9adccb27 926 #'(lambda (boolean)
927 (not (zerop boolean))))
928
75689fea 929(define-type-method writer-function ((type boolean))
930 (destructuring-bind (&optional (size '*))
931 (rest (mklist (type-expand-to 'boolean type)))
932 (let ((writer (writer-function `(signed-byte ,size))))
933 #'(lambda (boolean location &optional (offset 0))
934 (funcall writer (if boolean 1 0) location offset)))))
935
936(define-type-method reader-function ((type boolean))
937 (destructuring-bind (&optional (size '*))
938 (rest (mklist (type-expand-to 'boolean type)))
939 (let ((reader (reader-function `(signed-byte ,size))))
940 #'(lambda (location &optional (offset 0) weak-p)
941 (declare (ignore weak-p))
942 (not (zerop (funcall reader location offset)))))))
943
944
945(define-type-method alien-type ((type or))
946 (let* ((expanded-type (type-expand-to 'or type))
947 (alien-type (alien-type (second expanded-type))))
9adccb27 948 (unless (every #'(lambda (type)
949 (eq alien-type (alien-type type)))
75689fea 950 (cddr expanded-type))
951 (error "No common alien type specifier for union type: ~A" type))
310da1d5 952 alien-type))
953
75689fea 954(define-type-method size-of ((type or))
955 (size-of (second (type-expand-to 'or type))))
9adccb27 956
75689fea 957(define-type-method to-alien-form ((type or) form)
9adccb27 958 `(let ((value ,form))
75689fea 959 (etypecase value
960 ,@(mapcar
961 #'(lambda (type)
962 `(,type ,(to-alien-form type 'value)))
963 (rest (type-expand-to 'or type))))))
964
965(define-type-method to-alien-function ((type or))
966 (let* ((expanded-type (type-expand-to 'or type))
967 (functions (mapcar #'to-alien-function (rest expanded-type))))
9adccb27 968 #'(lambda (value)
969 (loop
970 for function in functions
75689fea 971 for alt-type in (rest expanded-type)
972 when (typep value alt-type)
9adccb27 973 do (return (funcall function value))
75689fea 974 finally (error "~S is not of type ~A" value type)))))
975
9adccb27 976
75689fea 977(define-type-method alien-type ((type pointer))
978 (declare (ignore type))
310da1d5 979 'system-area-pointer)
980
75689fea 981(define-type-method size-of ((type pointer))
982 (declare (ignore type))
9adccb27 983 +size-of-pointer+)
310da1d5 984
75689fea 985(define-type-method to-alien-form ((type pointer) form)
986 (declare (ignore type))
987 form)
988
989(define-type-method to-alien-function ((type pointer))
990 (declare (ignore type))
991 #'identity)
992
993(define-type-method from-alien-form ((type pointer) form)
994 (declare (ignore type))
995 form)
996
997(define-type-method from-alien-function ((type pointer))
998 (declare (ignore type))
999 #'identity)
1000
1001(define-type-method writer-function ((type pointer))
1002 (declare (ignore type))
9adccb27 1003 #'(lambda (sap location &optional (offset 0))
1004 (setf (sap-ref-sap location offset) sap)))
310da1d5 1005
75689fea 1006(define-type-method reader-function ((type pointer))
1007 (declare (ignore type))
3005806e 1008 #'(lambda (location &optional (offset 0) weak-p)
1009 (declare (ignore weak-p))
9adccb27 1010 (sap-ref-sap location offset)))
310da1d5 1011
1012
75689fea 1013(define-type-method alien-type ((type null))
1014 (declare (ignore type))
9adccb27 1015 (alien-type 'pointer))
310da1d5 1016
75689fea 1017(define-type-method size-of ((type null))
1018 (declare (ignore type))
9adccb27 1019 (size-of 'pointer))
1020
75689fea 1021(define-type-method to-alien-form ((type null) null)
1022 (declare (ignore null type))
310da1d5 1023 `(make-pointer 0))
1024
75689fea 1025(define-type-method to-alien-function ((type null))
1026 (declare (ignore type))
9adccb27 1027 #'(lambda (null)
1028 (declare (ignore null))
1029 (make-pointer 0)))
310da1d5 1030
310da1d5 1031
75689fea 1032(define-type-method alien-type ((type nil))
1033 (declare (ignore type))
73572c12 1034 'void)
9adccb27 1035
75689fea 1036(define-type-method from-alien-function ((type nil))
1037 (declare (ignore type))
9adccb27 1038 #'(lambda (value)
1039 (declare (ignore value))
1040 (values)))
9ca5565a 1041
75689fea 1042(define-type-method to-alien-form ((type nil) form)
9ca5565a 1043 (declare (ignore type))
75689fea 1044 form)
9ca5565a 1045
9ca5565a 1046
75689fea 1047(define-type-method to-alien-form ((type copy-of) form)
1048 (copy-to-alien-form (second (type-expand-to 'copy-of type)) form))
9ca5565a 1049
75689fea 1050(define-type-method to-alien-function ((type copy-of))
1051 (copy-to-alien-function (second (type-expand-to 'copy-of type))))
9ca5565a 1052
75689fea 1053(define-type-method from-alien-form ((type copy-of) form)
1054 (copy-from-alien-form (second (type-expand-to 'copy-of type)) form))
9ca5565a 1055
75689fea 1056(define-type-method from-alien-function ((type copy-of))
1057 (copy-from-alien-function (second (type-expand-to 'copy-of type))))
9ca5565a 1058
1dc849d7 1059(define-type-method cleanup-function ((type copy-of))
1060 (declare (ignore type))
1061 #'identity)
1062
1063(define-type-method destroy-function ((type copy-of))
1064 (declare (ignore type))
1065 #'(lambda (location &optional offset)
1066 (declare (ignore location offset))))
1067
cdd375f3 1068
75689fea 1069(define-type-method alien-type ((type callback))
cdd375f3 1070 (declare (ignore type))
46759268 1071 (alien-type 'pointer))
1072
75689fea 1073(define-type-method to-alien-form ((type callback) callback)
1074 (declare (ignore type ))
586328b4 1075 `(callback-address ,callback))