chiark / gitweb /
Custom types are now re-registered when a saved image is loaded
[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
ac837454 23;; $Id: ffi.lisp,v 1.30 2006/03/03 20:31:24 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
6eb2183d 351 (unless (get ',name 'type-methods)
352 (setf (get ',name 'type-methods) (make-hash-table))
353 (setf (get ',name 'built-in-type-hierarchy) ()))
4d1fea77 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)
6baf860c 377 "Creates a form to clean up after the alien call has finished.")
4d1fea77 378(define-type-generic callback-from-alien-form (type-spec form))
379(define-type-generic callback-cleanup-form (type-spec form))
fc358945 380
4d1fea77 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))
fc358945 384
4d1fea77 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))
508d13a7 392
4d1fea77 393(define-type-generic unbound-value (type-spec)
394 "Returns a value which should be intepreted as unbound for slots with virtual allocation")
b6bf802c 395
fc358945 396
fb9bc912 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
7bde5a67 407;; Sizes of fundamental C types in bytes (8 bits)
fb9bc912 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
7bde5a67 427
428;; Sizes of fundamental C types in bits
429(defconstant +bits-of-byte+ 8)
fb9bc912 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)
7bde5a67 439
440
6baf860c 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)
4d1fea77 451(deftype boolean (&optional (size '*)) (declare (ignore size)) t)
452(deftype copy-of (type) type)
fc358945 453
4d1fea77 454(define-type-method alien-type ((type t))
455 (error "No alien type corresponding to the type specifier ~A" type))
fc358945 456
4d1fea77 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))
fc358945 460
4d1fea77 461(define-type-method to-alien-function ((type t))
462 (error "Not a valid type specifier for arguments: ~A" type))
fc358945 463
4d1fea77 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))
fc358945 467
4d1fea77 468(define-type-method from-alien-function ((type t))
469 (error "Not a valid type specifier for return values: ~A" type))
6baf860c 470
4d1fea77 471(define-type-method cleanup-form ((type t) form)
472 (declare (ignore form type))
6baf860c 473 nil)
fc358945 474
4d1fea77 475(define-type-method cleanup-function ((type t))
476 (declare (ignore type))
6baf860c 477 #'identity)
478
4d1fea77 479(define-type-method callback-from-alien-form ((type t) form)
480 (copy-from-alien-form type form))
ae17423c 481
4d1fea77 482(define-type-method callback-cleanup-form ((type t) form)
483 (declare (ignore form type))
ae17423c 484 nil)
485
4d1fea77 486(define-type-method destroy-function ((type t))
487 (declare (ignore type))
4c795125 488 #'(lambda (location &optional offset)
6baf860c 489 (declare (ignore location offset))))
490
4d1fea77 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))
508d13a7 496
4d1fea77 497(define-type-method copy-from-alien-form ((type t) form)
498 (from-alien-form type form))
508d13a7 499
4d1fea77 500(define-type-method copy-from-alien-function ((type t))
501 (from-alien-function type))
508d13a7 502
508d13a7 503
4d1fea77 504(define-type-method to-alien-form ((type real) form)
6baf860c 505 (declare (ignore type))
4d1fea77 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)))
6baf860c 541 (ecase size
3d36c5d6 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))))
6baf860c 546
4d1fea77 547(define-type-method size-of ((type signed-byte))
548 (destructuring-bind (&optional (size '*))
549 (rest (mklist (type-expand-to 'signed-byte type)))
6baf860c 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
4d1fea77 556(define-type-method writer-function ((type signed-byte))
557 (destructuring-bind (&optional (size '*))
558 (rest (mklist (type-expand-to 'signed-byte type)))
6baf860c 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
4d1fea77 570(define-type-method reader-function ((type signed-byte))
571 (destructuring-bind (&optional (size '*))
572 (rest (mklist (type-expand-to 'signed-byte type)))
6baf860c 573 (let ((size (if (eq size '*) +bits-of-int+ size)))
574 (ecase size
0739b019 575 (8 #'(lambda (sap &optional (offset 0) weak-p)
576 (declare (ignore weak-p))
6baf860c 577 (signed-sap-ref-8 sap offset)))
0739b019 578 (16 #'(lambda (sap &optional (offset 0) weak-p)
579 (declare (ignore weak-p))
6baf860c 580 (signed-sap-ref-16 sap offset)))
0739b019 581 (32 #'(lambda (sap &optional (offset 0) weak-p)
582 (declare (ignore weak-p))
6baf860c 583 (signed-sap-ref-32 sap offset)))
0739b019 584 (64 #'(lambda (sap &optional (offset 0) weak-p)
585 (declare (ignore weak-p))
6baf860c 586 (signed-sap-ref-64 sap offset)))))))
587
4d1fea77 588
589(define-type-method alien-type ((type unsigned-byte))
590 (destructuring-bind (&optional (size '*))
591 (rest (mklist (type-expand-to 'unsigned-byte type)))
6baf860c 592 (ecase size
3d36c5d6 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))))
6baf860c 600
6baf860c 601
4d1fea77 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)))
6baf860c 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
4d1fea77 621(define-type-method reader-function ((type unsigned-byte))
622 (destructuring-bind (&optional (size '*))
623 (rest (mklist (type-expand-to 'unsigned-byte type)))
6baf860c 624 (let ((size (if (eq size '*) +bits-of-int+ size)))
625 (ecase size
0739b019 626 (8 #'(lambda (sap &optional (offset 0) weak-p)
627 (declare (ignore weak-p))
6baf860c 628 (sap-ref-8 sap offset)))
0739b019 629 (16 #'(lambda (sap &optional (offset 0) weak-p)
630 (declare (ignore weak-p))
6baf860c 631 (sap-ref-16 sap offset)))
0739b019 632 (32 #'(lambda (sap &optional (offset 0) weak-p)
633 (declare (ignore weak-p))
6baf860c 634 (sap-ref-32 sap offset)))
0739b019 635 (64 #'(lambda (sap &optional (offset 0) weak-p)
636 (declare (ignore weak-p))
6baf860c 637 (sap-ref-64 sap offset)))))))
42c6b247 638
4d1fea77 639(define-type-method alien-type ((type single-float))
640 (declare (ignore type))
3d36c5d6 641 #+cmu 'alien:single-float #+sbcl 'sb-alien:single-float)
fc358945 642
4d1fea77 643(define-type-method size-of ((type single-float))
644 (declare (ignore type))
fc358945 645 +size-of-float+)
646
4d1fea77 647(define-type-method to-alien-form ((type single-float) form)
648 (declare (ignore type))
472e1aae 649 `(coerce ,form 'single-float))
650
4d1fea77 651(define-type-method to-alien-function ((type single-float))
652 (declare (ignore type))
472e1aae 653 #'(lambda (number)
654 (coerce number 'single-float)))
655
4d1fea77 656(define-type-method writer-function ((type single-float))
657 (declare (ignore type))
6baf860c 658 #'(lambda (value location &optional (offset 0))
7bde5a67 659 (setf (sap-ref-single location offset) (coerce value 'single-float))))
fc358945 660
4d1fea77 661(define-type-method reader-function ((type single-float))
662 (declare (ignore type))
0739b019 663 #'(lambda (sap &optional (offset 0) weak-p)
664 (declare (ignore weak-p))
6baf860c 665 (sap-ref-single sap offset)))
fc358945 666
667
4d1fea77 668(define-type-method alien-type ((type double-float))
669 (declare (ignore type))
3d36c5d6 670 #+cmu 'alien:double-float #+sbcl 'sb-alien:double-float)
fc358945 671
4d1fea77 672(define-type-method size-of ((type double-float))
673 (declare (ignore type))
5b50f177 674 +size-of-double+)
fc358945 675
4d1fea77 676(define-type-method to-alien-form ((type double-float) form)
677 (declare (ignore type))
472e1aae 678 `(coerce ,form 'double-float))
679
4d1fea77 680(define-type-method to-alien-function ((type double-float))
681 (declare (ignore type))
472e1aae 682 #'(lambda (number)
683 (coerce number 'double-float)))
684
4d1fea77 685(define-type-method writer-function ((type double-float))
686 (declare (ignore type))
6baf860c 687 #'(lambda (value location &optional (offset 0))
688 (setf (sap-ref-double location offset) (coerce value 'double-float))))
fc358945 689
4d1fea77 690(define-type-method reader-function ((type double-float))
691 (declare (ignore type))
0739b019 692 #'(lambda (sap &optional (offset 0) weak-p)
693 (declare (ignore weak-p))
6baf860c 694 (sap-ref-double sap offset)))
fc358945 695
696
4d1fea77 697(define-type-method alien-type ((type base-char))
698 (declare (ignore type))
3d36c5d6 699 #+cmu 'c-call:char #+sbcl 'sb-alien:char)
fc358945 700
4d1fea77 701(define-type-method size-of ((type base-char))
702 (declare (ignore type))
fc358945 703 1)
704
4d1fea77 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))
6baf860c 723 #'(lambda (char location &optional (offset 0))
724 (setf (sap-ref-8 location offset) (char-code char))))
fc358945 725
4d1fea77 726(define-type-method reader-function ((type base-char))
727 (declare (ignore type))
0739b019 728 #'(lambda (location &optional (offset 0) weak-p)
729 (declare (ignore weak-p))
6baf860c 730 (code-char (sap-ref-8 location offset))))
fc358945 731
732
4d1fea77 733(define-type-method alien-type ((type string))
734 (declare (ignore type))
6baf860c 735 (alien-type 'pointer))
fc358945 736
4d1fea77 737(define-type-method size-of ((type string))
738 (declare (ignore type))
6baf860c 739 (size-of 'pointer))
fc358945 740
4d1fea77 741(define-type-method to-alien-form ((type string) string)
742 (declare (ignore type))
fc358945 743 `(let ((string ,string))
744 ;; Always copy strings to prevent seg fault due to GC
a9bb8f02 745 #+cmu
fc358945 746 (copy-memory
3d36c5d6 747 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 748 (1+ (length string)))
749 #+sbcl
750 (let ((utf8 (%deport-utf8-string string)))
751 (copy-memory (vector-sap utf8) (length utf8)))))
fc358945 752
4d1fea77 753(define-type-method to-alien-function ((type string))
754 (declare (ignore type))
6baf860c 755 #'(lambda (string)
a9bb8f02 756 #+cmu
6baf860c 757 (copy-memory
3d36c5d6 758 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 759 (1+ (length string)))
760 #+sbcl
761 (let ((utf8 (%deport-utf8-string string)))
762 (copy-memory (vector-sap utf8) (length utf8)))))
6baf860c 763
4d1fea77 764(define-type-method from-alien-form ((type string) string)
765 (declare (ignore type))
6baf860c 766 `(let ((string ,string))
767 (unless (null-pointer-p string)
508d13a7 768 (prog1
a9bb8f02 769 #+cmu(%naturalize-c-string string)
770 #+sbcl(%naturalize-utf8-string string)
508d13a7 771 (deallocate-memory string)))))
fc358945 772
4d1fea77 773(define-type-method from-alien-function ((type string))
774 (declare (ignore type))
6baf860c 775 #'(lambda (string)
776 (unless (null-pointer-p string)
508d13a7 777 (prog1
a9bb8f02 778 #+cmu(%naturalize-c-string string)
779 #+sbcl(%naturalize-utf8-string string)
508d13a7 780 (deallocate-memory string)))))
fc358945 781
4d1fea77 782(define-type-method cleanup-form ((type string) string)
783 (declare (ignore type))
6baf860c 784 `(let ((string ,string))
785 (unless (null-pointer-p string)
786 (deallocate-memory string))))
787
4d1fea77 788(define-type-method cleanup-function ((type string))
789 (declare (ignore type))
6baf860c 790 #'(lambda (string)
791 (unless (null-pointer-p string)
792 (deallocate-memory string))))
793
4d1fea77 794(define-type-method copy-from-alien-form ((type string) string)
795 (declare (ignore type))
508d13a7 796 `(let ((string ,string))
797 (unless (null-pointer-p string)
a9bb8f02 798 #+cmu(%naturalize-c-string string)
799 #+sbcl(%naturalize-utf8-string string))))
508d13a7 800
4d1fea77 801(define-type-method copy-from-alien-function ((type string))
802 (declare (ignore type))
508d13a7 803 #'(lambda (string)
804 (unless (null-pointer-p string)
a9bb8f02 805 #+cmu(%naturalize-c-string string)
806 #+sbcl(%naturalize-utf8-string string))))
508d13a7 807
4d1fea77 808(define-type-method writer-function ((type string))
809 (declare (ignore type))
6baf860c 810 #'(lambda (string location &optional (offset 0))
811 (assert (null-pointer-p (sap-ref-sap location offset)))
812 (setf (sap-ref-sap location offset)
a9bb8f02 813 #+cmu
6baf860c 814 (copy-memory
3d36c5d6 815 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 816 (1+ (length string)))
817 #+sbcl
818 (let ((utf8 (%deport-utf8-string string)))
819 (copy-memory (vector-sap utf8) (length utf8))))))
6baf860c 820
4d1fea77 821(define-type-method reader-function ((type string))
822 (declare (ignore type))
0739b019 823 #'(lambda (location &optional (offset 0) weak-p)
824 (declare (ignore weak-p))
6baf860c 825 (unless (null-pointer-p (sap-ref-sap location offset))
a9bb8f02 826 #+cmu(%naturalize-c-string (sap-ref-sap location offset))
827 #+sbcl(%naturalize-utf8-string (sap-ref-sap location offset)))))
6baf860c 828
4d1fea77 829(define-type-method destroy-function ((type string))
830 (declare (ignore type))
6baf860c 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
4d1fea77 836(define-type-method unbound-value ((type string))
837 (declare (ignore type))
838 nil)
6baf860c 839
a9bb8f02 840
4d1fea77 841(define-type-method alien-type ((type pathname))
842 (declare (ignore type))
6baf860c 843 (alien-type 'string))
844
4d1fea77 845(define-type-method size-of ((type pathname))
846 (declare (ignore type))
6baf860c 847 (size-of 'string))
fc358945 848
4d1fea77 849(define-type-method to-alien-form ((type pathname) path)
850 (declare (ignore type))
851 (to-alien-form 'string `(namestring (translate-logical-pathname ,path))))
6baf860c 852
4d1fea77 853(define-type-method to-alien-function ((type pathname))
854 (declare (ignore type))
6baf860c 855 (let ((string-function (to-alien-function 'string)))
856 #'(lambda (path)
857 (funcall string-function (namestring path)))))
858
4d1fea77 859(define-type-method from-alien-form ((type pathname) string)
860 (declare (ignore type))
861 `(parse-namestring ,(from-alien-form 'string string)))
6baf860c 862
4d1fea77 863(define-type-method from-alien-function ((type pathname))
864 (declare (ignore type))
6baf860c 865 (let ((string-function (from-alien-function 'string)))
866 #'(lambda (string)
867 (parse-namestring (funcall string-function string)))))
868
4d1fea77 869(define-type-method cleanup-form ((type pathnanme) string)
870 (declare (ignore type))
871 (cleanup-form 'string string))
6baf860c 872
4d1fea77 873(define-type-method cleanup-function ((type pathnanme))
874 (declare (ignore type))
6baf860c 875 (cleanup-function 'string))
876
4d1fea77 877(define-type-method writer-function ((type pathname))
878 (declare (ignore type))
6baf860c 879 (let ((string-writer (writer-function 'string)))
880 #'(lambda (path location &optional (offset 0))
881 (funcall string-writer (namestring path) location offset))))
882
4d1fea77 883(define-type-method reader-function ((type pathname))
884 (declare (ignore type))
6baf860c 885 (let ((string-reader (reader-function 'string)))
0739b019 886 #'(lambda (location &optional (offset 0) weak-p)
887 (declare (ignore weak-p))
6baf860c 888 (let ((string (funcall string-reader location offset)))
889 (when string
890 (parse-namestring string))))))
891
4d1fea77 892(define-type-method destroy-function ((type pathname))
893 (declare (ignore type))
6baf860c 894 (destroy-function 'string))
895
4d1fea77 896(define-type-method unbound-value ((type pathname))
897 (declare (ignore type))
b6bf802c 898 (unbound-value 'string))
899
6baf860c 900
4d1fea77 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))))
6baf860c 905
4d1fea77 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))))
6baf860c 910
4d1fea77 911(define-type-method to-alien-form ((type boolean) boolean)
912 (declare (ignore type))
fc358945 913 `(if ,boolean 1 0))
914
4d1fea77 915(define-type-method to-alien-function ((type boolean))
916 (declare (ignore type))
6baf860c 917 #'(lambda (boolean)
918 (if boolean 1 0)))
919
4d1fea77 920(define-type-method from-alien-form ((type boolean) boolean)
921 (declare (ignore type))
6baf860c 922 `(not (zerop ,boolean)))
923
4d1fea77 924(define-type-method from-alien-function ((type boolean))
925 (declare (ignore type))
6baf860c 926 #'(lambda (boolean)
927 (not (zerop boolean))))
928
4d1fea77 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))))
6baf860c 948 (unless (every #'(lambda (type)
949 (eq alien-type (alien-type type)))
4d1fea77 950 (cddr expanded-type))
951 (error "No common alien type specifier for union type: ~A" type))
fc358945 952 alien-type))
953
4d1fea77 954(define-type-method size-of ((type or))
955 (size-of (second (type-expand-to 'or type))))
6baf860c 956
4d1fea77 957(define-type-method to-alien-form ((type or) form)
6baf860c 958 `(let ((value ,form))
4d1fea77 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))))
6baf860c 968 #'(lambda (value)
969 (loop
970 for function in functions
4d1fea77 971 for alt-type in (rest expanded-type)
972 when (typep value alt-type)
6baf860c 973 do (return (funcall function value))
4d1fea77 974 finally (error "~S is not of type ~A" value type)))))
975
6baf860c 976
4d1fea77 977(define-type-method alien-type ((type pointer))
978 (declare (ignore type))
fc358945 979 'system-area-pointer)
980
4d1fea77 981(define-type-method size-of ((type pointer))
982 (declare (ignore type))
6baf860c 983 +size-of-pointer+)
fc358945 984
4d1fea77 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))
6baf860c 1003 #'(lambda (sap location &optional (offset 0))
1004 (setf (sap-ref-sap location offset) sap)))
fc358945 1005
4d1fea77 1006(define-type-method reader-function ((type pointer))
1007 (declare (ignore type))
0739b019 1008 #'(lambda (location &optional (offset 0) weak-p)
1009 (declare (ignore weak-p))
6baf860c 1010 (sap-ref-sap location offset)))
fc358945 1011
1012
4d1fea77 1013(define-type-method alien-type ((type null))
1014 (declare (ignore type))
6baf860c 1015 (alien-type 'pointer))
fc358945 1016
4d1fea77 1017(define-type-method size-of ((type null))
1018 (declare (ignore type))
6baf860c 1019 (size-of 'pointer))
1020
4d1fea77 1021(define-type-method to-alien-form ((type null) null)
1022 (declare (ignore null type))
fc358945 1023 `(make-pointer 0))
1024
4d1fea77 1025(define-type-method to-alien-function ((type null))
1026 (declare (ignore type))
6baf860c 1027 #'(lambda (null)
1028 (declare (ignore null))
1029 (make-pointer 0)))
fc358945 1030
fc358945 1031
4d1fea77 1032(define-type-method alien-type ((type nil))
1033 (declare (ignore type))
3d36c5d6 1034 'void)
6baf860c 1035
4d1fea77 1036(define-type-method from-alien-function ((type nil))
1037 (declare (ignore type))
6baf860c 1038 #'(lambda (value)
1039 (declare (ignore value))
1040 (values)))
508d13a7 1041
4d1fea77 1042(define-type-method to-alien-form ((type nil) form)
508d13a7 1043 (declare (ignore type))
4d1fea77 1044 form)
508d13a7 1045
508d13a7 1046
4d1fea77 1047(define-type-method to-alien-form ((type copy-of) form)
1048 (copy-to-alien-form (second (type-expand-to 'copy-of type)) form))
508d13a7 1049
4d1fea77 1050(define-type-method to-alien-function ((type copy-of))
1051 (copy-to-alien-function (second (type-expand-to 'copy-of type))))
508d13a7 1052
4d1fea77 1053(define-type-method from-alien-form ((type copy-of) form)
1054 (copy-from-alien-form (second (type-expand-to 'copy-of type)) form))
508d13a7 1055
4d1fea77 1056(define-type-method from-alien-function ((type copy-of))
1057 (copy-from-alien-function (second (type-expand-to 'copy-of type))))
508d13a7 1058
ac837454 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
4c795125 1068
4d1fea77 1069(define-type-method alien-type ((type callback))
4c795125 1070 (declare (ignore type))
ff8fa451 1071 (alien-type 'pointer))
1072
4d1fea77 1073(define-type-method to-alien-form ((type callback) callback)
1074 (declare (ignore type ))
ae17423c 1075 `(callback-address ,callback))