chiark / gitweb /
Custom types are now re-registered when a saved image is loaded
[clg] / glib / proxy.lisp
CommitLineData
55212af1 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 2000-2005 Espen S. Johnsen <espen@users.sf.net>
b44caf77 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:
b44caf77 11;;
55212af1 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
b44caf77 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.
b44caf77 22
a968b115 23;; $Id: proxy.lisp,v 1.39 2006/03/06 14:28:03 espen Exp $
b44caf77 24
25(in-package "GLIB")
26
b44caf77 27;;;; Superclass for all metaclasses implementing some sort of virtual slots
28
29(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 30 (defclass virtual-slots-class (standard-class)
935a783c 31 ())
b44caf77 32
33 (defclass direct-virtual-slot-definition (standard-direct-slot-definition)
ba25fa44 34 ((setter :reader slot-definition-setter :initarg :setter)
935a783c 35 (getter :reader slot-definition-getter :initarg :getter)
64bce834 36 (unbound :reader slot-definition-unbound :initarg :unbound)
935a783c 37 (boundp :reader slot-definition-boundp :initarg :boundp)))
b44caf77 38
935a783c 39 (defclass effective-virtual-slot-definition (standard-effective-slot-definition)
40 ((setter :reader slot-definition-setter :initarg :setter)
41 (getter :reader slot-definition-getter :initarg :getter)
64bce834 42 (unbound :reader slot-definition-unbound :initarg :unbound)
82defe4d 43 (boundp :reader slot-definition-boundp :initarg :boundp)))
935a783c 44
82defe4d 45 (defclass direct-special-slot-definition (standard-direct-slot-definition)
c23cc486 46 ((special :initarg :special :accessor slot-definition-special)))
b44caf77 47
82defe4d 48 (defclass effective-special-slot-definition (standard-effective-slot-definition)
c23cc486 49 ((special :initarg :special :accessor slot-definition-special))))
82defe4d 50
51(defvar *unbound-marker* (gensym "UNBOUND-MARKER-"))
52
53(defun most-specific-slot-value (instances slot &optional (default *unbound-marker*))
54 (let ((object (find-if
55 #'(lambda (ob)
56 (and (slot-exists-p ob slot) (slot-boundp ob slot)))
57 instances)))
58 (if object
59 (slot-value object slot)
60 default)))
61
b44caf77 62
6baf860c 63(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
c23cc486 64 (cond
65 ((eq (getf initargs :allocation) :virtual)
66 (find-class 'direct-virtual-slot-definition))
67 ((getf initargs :special)
68 (find-class 'direct-special-slot-definition))
69 (t (call-next-method))))
b44caf77 70
6baf860c 71(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
c23cc486 72 (cond
73 ((eq (getf initargs :allocation) :virtual)
74 (find-class 'effective-virtual-slot-definition))
75 ((getf initargs :special)
76 (find-class 'effective-special-slot-definition))
77 (t (call-next-method))))
b44caf77 78
935a783c 79
80(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
64bce834 81 (if (not (slot-boundp slotd 'getter))
82 (setf
935a783c 83 (slot-value slotd 'reader-function)
64bce834 84 #'(lambda (object)
85 (declare (ignore object))
adcadd53 86 (error "Slot is not readable: ~A" (slot-definition-name slotd)))
64bce834 87 (slot-value slotd 'boundp-function)
88 #'(lambda (object) (declare (ignore object)) nil))
89
90 (let ((getter-function
91 (let ((getter (slot-value slotd 'getter)))
92 (etypecase getter
93 (function getter)
94 (symbol
95 #'(lambda (object)
96 (funcall getter object)))
97 (string
98 (let ((reader nil))
99 (setf (slot-value slotd 'reader-function)
100 #'(lambda (object)
101 (unless reader
b6bf802c 102 (setq reader
103 (mkbinding getter
104 (slot-definition-type slotd) 'pointer)))
7ce0497d 105 (funcall reader (foreign-location object))))))))))
64bce834 106
935a783c 107 (setf
64bce834 108 (slot-value slotd 'boundp-function)
109 (cond
64bce834 110 ((slot-boundp slotd 'unbound)
111 (let ((unbound-value (slot-value slotd 'unbound)))
b6bf802c 112 #'(lambda (object)
113 (not (eq (funcall getter-function object) unbound-value)))))
114 ((slot-boundp slotd 'boundp)
115 (let ((boundp (slot-value slotd 'boundp)))
64bce834 116 (etypecase boundp
117 (function boundp)
118 (symbol #'(lambda (object)
119 (funcall boundp object)))
120 (string (let ((reader ()))
121 #'(lambda (object)
122 (unless reader
123 (setq reader
124 (mkbinding boundp
125 (slot-definition-type slotd) 'pointer)))
7ce0497d 126 (funcall reader (foreign-location object))))))))
4d1fea77 127 ((let ((unbound-value-method
128 (find-applicable-type-method 'unbound-value
129 (slot-definition-type slotd) nil)))
130 (when unbound-value-method
131 (let ((unbound-value
132 (funcall unbound-value-method (slot-definition-type slotd))))
133 #'(lambda (object)
134 (not (eq (funcall getter-function object) unbound-value)))))))
b6bf802c 135 (#'(lambda (object) (declare (ignore object)) t))))
64bce834 136
137 (setf
138 (slot-value slotd 'reader-function)
139 (cond
140 ((slot-boundp slotd 'unbound)
141 (let ((unbound (slot-value slotd 'unbound))
142 (slot-name (slot-definition-name slotd)))
b6bf802c 143 #'(lambda (object)
144 (let ((value (funcall getter-function object)))
145 (if (eq value unbound)
146 (slot-unbound (class-of object) object slot-name)
147 value)))))
64bce834 148 ((slot-boundp slotd 'boundp)
149 (let ((boundp-function (slot-value slotd 'boundp-function)))
b6bf802c 150 #'(lambda (object)
151 (and
152 (funcall boundp-function object)
153 (funcall getter-function object)))))
4d1fea77 154 ((let ((unbound-value-method
155 (find-applicable-type-method 'unbound-value
156 (slot-definition-type slotd) nil)))
157 (when unbound-value-method
158 (let ((unbound-value
159 (funcall unbound-value-method (slot-definition-type slotd)))
160 (slot-name (slot-definition-name slotd)))
b6bf802c 161 #'(lambda (object)
162 (let ((value (funcall getter-function object)))
163 (if (eq value unbound-value)
164 (slot-unbound (class-of object) object slot-name)
165 value)))))))
64bce834 166 (getter-function)))))
167
168 (setf
169 (slot-value slotd 'writer-function)
170 (if (not (slot-boundp slotd 'setter))
adcadd53 171 #'(lambda (value object)
172 (declare (ignore value object))
173 (error "Slot is not writable: ~A" (slot-definition-name slotd)))
64bce834 174 (with-slots (setter) slotd
935a783c 175 (etypecase setter
176 (function setter)
64bce834 177 ((or symbol cons)
178 #'(lambda (value object)
179 (funcall (fdefinition setter) value object)))
0466f75e 180 (string
64bce834 181 (let ((writer ()))
182 (setf
183 (slot-value slotd 'writer-function)
184 #'(lambda (value object)
185 (unless writer
186 (setq writer
187 (mkbinding setter 'nil 'pointer
188 (slot-definition-type slotd))))
7ce0497d 189 (funcall writer (foreign-location object) value)))))))))
64bce834 190
3d2378de 191 #-sbcl>=0.9.8(initialize-internal-slot-gfs (slot-definition-name slotd)))
935a783c 192
193
194
64bce834 195(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
935a783c 196 nil)
197
6baf860c 198(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
c23cc486 199 (typecase (first direct-slotds)
200 (direct-virtual-slot-definition
201 (let ((initargs ()))
202 (let ((getter (most-specific-slot-value direct-slotds 'getter)))
203 (unless (eq getter *unbound-marker*)
204 (setf (getf initargs :getter) getter)))
205 (let ((setter (most-specific-slot-value direct-slotds 'setter)))
206 (unless (eq setter *unbound-marker*)
207 (setf (getf initargs :setter) setter)))
208 (let ((unbound (most-specific-slot-value direct-slotds 'unbound)))
209 (unless (eq unbound *unbound-marker*)
210 (setf (getf initargs :unbound) unbound)))
211 (let ((boundp (most-specific-slot-value direct-slotds 'boundp)))
212 (unless (eq boundp *unbound-marker*)
213 (setf (getf initargs :boundp) boundp)))
a968b115 214 ;; This is needed to avoid type expansion in SBCL version >= 0.9.8
215 #+sbcl>=0.9.8
216 (let ((type (most-specific-slot-value direct-slotds #-sbcl>=0.9.10'type #+sbcl>=0.9.10'sb-pcl::%type)))
f611f15f 217 (unless (eq type *unbound-marker*)
218 (setf (getf initargs :type) type)))
c23cc486 219 (nconc initargs (call-next-method))))
220 (direct-special-slot-definition
221 (append '(:special t) (call-next-method)))
222 (t (call-next-method))))
935a783c 223
b44caf77 224
b44caf77 225(defmethod slot-value-using-class
6baf860c 226 ((class virtual-slots-class) (object standard-object)
b44caf77 227 (slotd effective-virtual-slot-definition))
935a783c 228 (if (funcall (slot-value slotd 'boundp-function) object)
229 (funcall (slot-value slotd 'reader-function) object)
230 (slot-unbound class object (slot-definition-name slotd))))
b44caf77 231
b44caf77 232(defmethod slot-boundp-using-class
6baf860c 233 ((class virtual-slots-class) (object standard-object)
b44caf77 234 (slotd effective-virtual-slot-definition))
935a783c 235 (funcall (slot-value slotd 'boundp-function) object))
236
237(defmethod (setf slot-value-using-class)
6baf860c 238 (value (class virtual-slots-class) (object standard-object)
b44caf77 239 (slotd effective-virtual-slot-definition))
935a783c 240 (funcall (slot-value slotd 'writer-function) value object))
241
242
b44caf77 243(defmethod validate-superclass
6baf860c 244 ((class virtual-slots-class) (super standard-class))
b44caf77 245 t)
246
247
c23cc486 248(defmethod slot-definition-special ((slotd standard-direct-slot-definition))
249 (declare (ignore slotd))
250 nil)
251
252(defmethod slot-definition-special ((slotd standard-effective-slot-definition))
253 (declare (ignore slotd))
254 nil)
255
256
b44caf77 257;;;; Proxy cache
258
b44caf77 259(defvar *instance-cache* (make-hash-table :test #'eql))
260
a2bc0f3a 261(defun cache-instance (instance &optional (weak-ref t))
b44caf77 262 (setf
7ce0497d 263 (gethash (sap-int (foreign-location instance)) *instance-cache*)
a2bc0f3a 264 (if weak-ref
265 (make-weak-pointer instance)
266 instance)))
b44caf77 267
268(defun find-cached-instance (location)
3d36c5d6 269 (let ((ref (gethash (sap-int location) *instance-cache*)))
b44caf77 270 (when ref
a2bc0f3a 271 (if (weak-pointer-p ref)
272 (weak-pointer-value ref)
273 ref))))
b44caf77 274
a5c3a597 275(defun instance-cached-p (location)
3d36c5d6 276 (gethash (sap-int location) *instance-cache*))
a5c3a597 277
b44caf77 278(defun remove-cached-instance (location)
3d36c5d6 279 (remhash (sap-int location) *instance-cache*))
b44caf77 280
6baf860c 281;; For debuging
a2bc0f3a 282(defun list-cached-instances ()
6baf860c 283 (let ((instances ()))
284 (maphash #'(lambda (location ref)
285 (declare (ignore location))
a2bc0f3a 286 (push ref instances))
6baf860c 287 *instance-cache*)
288 instances))
289
2a9afe6f 290;; Instances that gets invalidated tend to be short lived, but created
291;; in large numbers. So we're keeping them in a hash table to be able
292;; to reuse them (and thus reduce consing)
293(defvar *invalidated-instance-cache* (make-hash-table :test #'eql))
294
295(defun cache-invalidated-instance (instance)
296 (push instance
297 (gethash (class-of instance) *invalidated-instance-cache*)))
298
299(defun find-invalidated-instance (class)
300 (when (gethash class *invalidated-instance-cache*)
301 (pop (gethash class *invalidated-instance-cache*))))
302
303(defun list-invalidated-instances ()
304 (let ((instances ()))
305 (maphash #'(lambda (location ref)
306 (declare (ignore location))
307 (push ref instances))
308 *invalidated-instance-cache*)
309 instances))
310
b44caf77 311
312
313;;;; Proxy for alien instances
314
253c1339 315;; TODO: add a ref-counted-proxy subclass
6baf860c 316(defclass proxy ()
c23cc486 317 ((location :special t :type pointer))
82defe4d 318 (:metaclass virtual-slots-class))
b44caf77 319
6baf860c 320(defgeneric instance-finalizer (object))
321(defgeneric reference-foreign (class location))
322(defgeneric unreference-foreign (class location))
253c1339 323(defgeneric invalidate-instance (object))
adcadd53 324(defgeneric allocate-foreign (object &key &allow-other-keys))
6baf860c 325
cf45719a 326(defun foreign-location (instance)
327 (slot-value instance 'location))
328
329(defun (setf foreign-location) (location instance)
330 (setf (slot-value instance 'location) location))
331
332(defun proxy-valid-p (instance)
333 (slot-boundp instance 'location))
334
c55abd76 335(defmethod reference-foreign ((name symbol) location)
336 (reference-foreign (find-class name) location))
337
338(defmethod unreference-foreign ((name symbol) location)
339 (unreference-foreign (find-class name) location))
340
6baf860c 341(defmethod unreference-foreign :around ((class class) location)
342 (unless (null-pointer-p location)
7ce0497d 343 (call-next-method)))
b44caf77 344
a5c3a597 345(defmethod print-object ((instance proxy) stream)
346 (print-unreadable-object (instance stream :type t :identity nil)
7ce0497d 347 (if (slot-boundp instance 'location)
348 (format stream "at 0x~X" (sap-int (foreign-location instance)))
4d1fea77 349 (write-string "at <unbound>" stream))))
b44caf77 350
adcadd53 351(defmethod initialize-instance :around ((instance proxy) &rest initargs &key &allow-other-keys)
352 (setf
353 (foreign-location instance)
354 (apply #'allocate-foreign instance initargs))
1d06a422 355 (prog1
356 (call-next-method)
357 (cache-instance instance)
358 (finalize instance (instance-finalizer instance))))
b44caf77 359
360(defmethod instance-finalizer ((instance proxy))
7ce0497d 361 (let ((location (foreign-location instance))
6baf860c 362 (class (class-of instance)))
363;; (unless (find-method #'unreference-foreign nil (list (class-of class) t) nil)
364;; (error "No matching method for UNREFERENCE-INSTANCE when called with class ~A" class))
365 #'(lambda ()
29933e83 366 (remove-cached-instance location)
6baf860c 367 (unreference-foreign class location))))
ba25fa44 368
2a9afe6f 369;; Any reference to the foreign object the instance may have held
370;; should be released before this method is invoked
253c1339 371(defmethod invalidate-instance ((instance proxy))
372 (remove-cached-instance (foreign-location instance))
2a9afe6f 373 (slot-makunbound instance 'location)
374 (cancel-finalization instance)
375 (cache-invalidated-instance instance))
253c1339 376
b44caf77 377
378;;;; Metaclass used for subclasses of proxy
379
3d36c5d6 380(defgeneric most-specific-proxy-superclass (class))
381(defgeneric direct-proxy-superclass (class))
382
383
b44caf77 384(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 385 (defclass proxy-class (virtual-slots-class)
7ce0497d 386 ((size :reader foreign-size)))
b44caf77 387
388 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
c23cc486 389 ((offset :reader slot-definition-offset :initarg :offset))
390 (:default-initargs :allocation :alien))
b44caf77 391
392 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
935a783c 393 ((offset :reader slot-definition-offset :initarg :offset)))
ba25fa44 394
b44caf77 395 (defmethod most-specific-proxy-superclass ((class proxy-class))
396 (find-if
397 #'(lambda (class)
398 (subtypep (class-name class) 'proxy))
935a783c 399 (cdr (compute-class-precedence-list class))))
3d36c5d6 400
ba25fa44 401 (defmethod direct-proxy-superclass ((class proxy-class))
402 (find-if
403 #'(lambda (class)
404 (subtypep (class-name class) 'proxy))
935a783c 405 (class-direct-superclasses class)))
406
64bce834 407 (defmethod shared-initialize ((class proxy-class) names &key size)
b44caf77 408 (call-next-method)
ba25fa44 409 (cond
935a783c 410 (size (setf (slot-value class 'size) (first size)))
6baf860c 411 ((slot-boundp class 'size) (slot-makunbound class 'size))))
7ce0497d 412
935a783c 413 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 414 (case (getf initargs :allocation)
82defe4d 415 (:alien (find-class 'direct-alien-slot-definition))
b44caf77 416 (t (call-next-method))))
935a783c 417
418 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 419 (case (getf initargs :allocation)
420 (:alien (find-class 'effective-alien-slot-definition))
b44caf77 421 (t (call-next-method))))
422
935a783c 423
424 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
c23cc486 425 (if (eq (slot-definition-allocation (first direct-slotds)) :alien)
935a783c 426 (nconc
427 (list :offset (most-specific-slot-value direct-slotds 'offset))
428 (call-next-method))
429 (call-next-method)))
430
431
432 (defmethod initialize-internal-slot-functions ((slotd effective-alien-slot-definition))
433 (with-slots (offset) slotd
6baf860c 434 (let ((type (slot-definition-type slotd)))
64bce834 435 (unless (slot-boundp slotd 'getter)
6baf860c 436 (let ((reader (reader-function type)))
437 (setf
64bce834 438 (slot-value slotd 'getter)
6baf860c 439 #'(lambda (object)
7ce0497d 440 (funcall reader (foreign-location object) offset)))))
935a783c 441
64bce834 442 (unless (slot-boundp slotd 'setter)
6baf860c 443 (let ((writer (writer-function type))
444 (destroy (destroy-function type)))
445 (setf
64bce834 446 (slot-value slotd 'setter)
6baf860c 447 #'(lambda (value object)
7ce0497d 448 (let ((location (foreign-location object)))
6baf860c 449 (funcall destroy location offset) ; destroy old value
64bce834 450 (funcall writer value location offset))))))))
451
935a783c 452 (call-next-method))
453
fb9bc912 454 (defconstant +struct-alignmen+
455 #+sbcl (/ (sb-alien-internals:alien-type-alignment
456 (sb-alien-internals:parse-alien-type
457 'system-area-pointer nil))
458 8)
459 #-sbcl 4)
b44caf77 460
7ce0497d 461 (defun align-offset (size)
462 (if (zerop (mod size +struct-alignmen+))
463 size
464 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
465
b44caf77 466 (defmethod compute-slots ((class proxy-class))
7ce0497d 467 (let ((alien-slots
468 (remove-if-not
469 #'(lambda (slotd)
470 (eq (slot-definition-allocation slotd) :alien))
471 (class-direct-slots class))))
472 (when alien-slots
473 (loop
474 as offset = (align-offset (foreign-size
475 (most-specific-proxy-superclass class)))
476 then (align-offset
477 (+
478 (slot-definition-offset slotd)
479 (size-of (slot-definition-type slotd))))
480 for slotd in alien-slots
481 unless (slot-boundp slotd 'offset)
482 do (setf (slot-value slotd 'offset) offset))))
b44caf77 483 (call-next-method))
8ae7ddc2 484
935a783c 485 (defmethod validate-superclass ((class proxy-class) (super standard-class))
486 (subtypep (class-name super) 'proxy))
487
7ce0497d 488 (defmethod foreign-size ((class-name symbol))
489 (foreign-size (find-class class-name))))
556b4a05 490
7ce0497d 491(defmethod foreign-size ((object proxy))
492 (foreign-size (class-of object)))
935a783c 493
7ce0497d 494
4d1fea77 495(define-type-method alien-type ((class proxy))
496 (declare (ignore class))
6baf860c 497 (alien-type 'pointer))
498
4d1fea77 499(define-type-method size-of ((class proxy))
500 (declare (ignore class))
6baf860c 501 (size-of 'pointer))
502
4d1fea77 503(define-type-method from-alien-form ((type proxy) location)
504 (let ((class (type-expand type)))
505 `(ensure-proxy-instance ',class ,location)))
6baf860c 506
4d1fea77 507(define-type-method from-alien-function ((type proxy))
508 (let ((class (type-expand type)))
509 #'(lambda (location)
510 (ensure-proxy-instance class location))))
b44caf77 511
4d1fea77 512(define-type-method to-alien-form ((type proxy) instance)
513 (declare (ignore type))
7ce0497d 514 `(foreign-location ,instance))
b44caf77 515
4d1fea77 516(define-type-method to-alien-function ((type proxy))
517 (declare (ignore type))
7ce0497d 518 #'foreign-location)
6baf860c 519
4d1fea77 520(define-type-method copy-from-alien-form ((type proxy) location)
521 (let ((class (type-expand type)))
522 `(ensure-proxy-instance ',class (reference-foreign ',class ,location))))
523
524(define-type-method copy-from-alien-function ((type proxy))
525 (let ((class (type-expand type)))
526 #'(lambda (location)
527 (ensure-proxy-instance class (reference-foreign class location)))))
528
529(define-type-method copy-to-alien-form ((type proxy) instance)
530 (let ((class (type-expand type)))
531 `(reference-foreign ',class (foreign-location ,instance))))
532
533(define-type-method copy-to-alien-function ((type proxy))
534 (let ((class (type-expand type)))
535 #'(lambda (instance)
536 (reference-foreign class (foreign-location instance)))))
537
538(define-type-method writer-function ((type proxy))
539 (let ((class (type-expand type)))
540 #'(lambda (instance location &optional (offset 0))
541 (assert (null-pointer-p (sap-ref-sap location offset)))
542 (setf
543 (sap-ref-sap location offset)
544 (reference-foreign class (foreign-location instance))))))
545
546(define-type-method reader-function ((type proxy))
547 (let ((class (type-expand type)))
548 #'(lambda (location &optional (offset 0) weak-p)
549 (declare (ignore weak-p))
550 (let ((instance (sap-ref-sap location offset)))
551 (unless (null-pointer-p instance)
552 (ensure-proxy-instance class (reference-foreign class instance)))))))
553
554(define-type-method destroy-function ((type proxy))
555 (let ((class (type-expand type)))
556 #'(lambda (location &optional (offset 0))
557 (unreference-foreign class (sap-ref-sap location offset)))))
558
559(define-type-method unbound-value ((type proxy))
560 (declare (ignore type))
561 nil)
6baf860c 562
1d06a422 563(defun ensure-proxy-instance (class location &rest initargs)
564 "Returns a proxy object representing the foreign object at the give
565location. If an existing object is not found in the cache
566MAKE-PROXY-INSTANCE is called to create one."
6baf860c 567 (unless (null-pointer-p location)
568 (or
e4a48e09 569 #-debug-ref-counting(find-cached-instance location)
570 #+debug-ref-counting
253c1339 571 (let ((instance (find-cached-instance location)))
572 (when instance
573 (format t "Object found in cache: ~A~%" instance)
574 instance))
1d06a422 575 (let ((instance (apply #'make-proxy-instance class location initargs)))
576 (cache-instance instance)
577 instance))))
578
579(defgeneric make-proxy-instance (class location &key weak)
580 (:documentation "Creates a new proxy object representing the foreign
581object at the give location. If WEAK is non NIL the foreign memory
582will not be released when the proxy is garbage collected."))
583
253c1339 584(defmethod make-proxy-instance ((class symbol) location &rest initargs)
585 (apply #'make-proxy-instance (find-class class) location initargs))
1d06a422 586
587(defmethod make-proxy-instance ((class proxy-class) location &key weak)
2a9afe6f 588 (let ((instance
589 (or
590 (find-invalidated-instance class)
591 (allocate-instance class))))
cf45719a 592 (setf (foreign-location instance) location)
1d06a422 593 (unless weak
594 (finalize instance (instance-finalizer instance)))
595 instance))
b44caf77 596
ba25fa44 597
598;;;; Superclasses for wrapping of C structures
b44caf77 599
6baf860c 600(defclass struct (proxy)
601 ()
7ce0497d 602 (:metaclass proxy-class)
603 (:size 0))
b44caf77 604
adcadd53 605(defmethod allocate-foreign ((struct struct) &rest initargs)
b44caf77 606 (declare (ignore initargs))
adcadd53 607 (let ((size (foreign-size (class-of struct))))
608 (if (zerop size)
609 (error "~A has zero size" (class-of struct))
610 (allocate-memory size))))
b44caf77 611
612
6baf860c 613;;;; Metaclasses used for subclasses of struct
614
4d1fea77 615(eval-when (:compile-toplevel :load-toplevel :execute)
616 (defclass struct-class (proxy-class)
617 ()))
b44caf77 618
82defe4d 619(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
620 (if (not (getf initargs :allocation))
621 (find-class 'direct-alien-slot-definition)
622 (call-next-method)))
623
6baf860c 624(defmethod reference-foreign ((class struct-class) location)
7ce0497d 625 (copy-memory location (foreign-size class)))
6baf860c 626
627(defmethod unreference-foreign ((class struct-class) location)
ba25fa44 628 (deallocate-memory location))
b44caf77 629
3d2378de 630(defmethod compute-slots :around ((class struct-class))
631 (let ((slots (call-next-method)))
632 (when (and
c23cc486 633 #-sbcl>=0.9.8(class-finalized-p class)
3d2378de 634 (not (slot-boundp class 'size)))
635 (let ((size (loop
636 for slotd in slots
637 when (eq (slot-definition-allocation slotd) :alien)
638 maximize (+
639 (slot-definition-offset slotd)
640 (size-of (slot-definition-type slotd))))))
641 (setf (slot-value class 'size) (+ size (mod size +struct-alignmen+)))))
642 slots))
7ce0497d 643
4d1fea77 644(define-type-method callback-from-alien-form ((type struct) form)
645 (let ((class (type-expand type)))
646 `(ensure-proxy-instance ',class ,form :weak t)))
647
648(define-type-method callback-cleanup-form ((type struct) form)
649 (declare (ignore type))
650 `(invalidate-instance ,form))
651
652(define-type-method reader-function ((type struct))
653 (let ((class (type-expand type)))
654 #'(lambda (location &optional (offset 0) weak-p)
655 (let ((instance (sap-ref-sap location offset)))
656 (unless (null-pointer-p instance)
657 (if weak-p
658 (ensure-proxy-instance class instance :weak t)
659 (ensure-proxy-instance class (reference-foreign class instance))))))))
253c1339 660
b44caf77 661
6baf860c 662(defclass static-struct-class (struct-class)
663 ())
b44caf77 664
6baf860c 665(defmethod reference-foreign ((class static-struct-class) location)
666 (declare (ignore class))
ba25fa44 667 location)
b44caf77 668
6baf860c 669(defmethod unreference-foreign ((class static-struct-class) location)
670 (declare (ignore class location))
ba25fa44 671 nil)
b4edcbf0 672
b4edcbf0 673;;; Pseudo type for structs which are inlined in other objects
674
4d1fea77 675(deftype inlined (type) type)
b4edcbf0 676
4d1fea77 677(define-type-method size-of ((type inlined))
75b6a08a 678 (let ((class (second (type-expand-to 'inlined type))))
4d1fea77 679 (foreign-size class)))
680
681(define-type-method reader-function ((type inlined))
75b6a08a 682 (let ((class (second (type-expand-to 'inlined type))))
0739b019 683 #'(lambda (location &optional (offset 0) weak-p)
684 (declare (ignore weak-p))
b4edcbf0 685 (ensure-proxy-instance class
686 (reference-foreign class (sap+ location offset))))))
687
4d1fea77 688(define-type-method writer-function ((type inlined))
75b6a08a 689 (let ((class (second (type-expand-to 'inlined type))))
253c1339 690 #'(lambda (instance location &optional (offset 0))
691 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
692
75b6a08a 693(define-type-method destroy-function ((type inlined))
694 (declare (ignore type))
695 #'(lambda (location &optional offset)
696 (declare (ignore location offset))))
697
698
b4edcbf0 699(export 'inlined)