Fixed build problem with SBCL 0.9.11
[clg] / glib / proxy.lisp
CommitLineData
112ac1d3 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 2000-2005 Espen S. Johnsen <espen@users.sf.net>
94f15c3c 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:
94f15c3c 11;;
112ac1d3 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
94f15c3c 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.
94f15c3c 22
46e84256 23;; $Id: proxy.lisp,v 1.39 2006-03-06 14:28:03 espen Exp $
94f15c3c 24
25(in-package "GLIB")
26
94f15c3c 27;;;; Superclass for all metaclasses implementing some sort of virtual slots
28
29(eval-when (:compile-toplevel :load-toplevel :execute)
9adccb27 30 (defclass virtual-slots-class (standard-class)
4d83a8a6 31 ())
94f15c3c 32
33 (defclass direct-virtual-slot-definition (standard-direct-slot-definition)
12d0437e 34 ((setter :reader slot-definition-setter :initarg :setter)
4d83a8a6 35 (getter :reader slot-definition-getter :initarg :getter)
eeda1c2d 36 (unbound :reader slot-definition-unbound :initarg :unbound)
4d83a8a6 37 (boundp :reader slot-definition-boundp :initarg :boundp)))
94f15c3c 38
4d83a8a6 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)
eeda1c2d 42 (unbound :reader slot-definition-unbound :initarg :unbound)
e2ebafb1 43 (boundp :reader slot-definition-boundp :initarg :boundp)))
4d83a8a6 44
e2ebafb1 45 (defclass direct-special-slot-definition (standard-direct-slot-definition)
b19bbc94 46 ((special :initarg :special :accessor slot-definition-special)))
94f15c3c 47
e2ebafb1 48 (defclass effective-special-slot-definition (standard-effective-slot-definition)
b19bbc94 49 ((special :initarg :special :accessor slot-definition-special))))
e2ebafb1 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
94f15c3c 62
9adccb27 63(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
b19bbc94 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))))
94f15c3c 70
9adccb27 71(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
b19bbc94 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))))
94f15c3c 78
4d83a8a6 79
80(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
eeda1c2d 81 (if (not (slot-boundp slotd 'getter))
82 (setf
4d83a8a6 83 (slot-value slotd 'reader-function)
eeda1c2d 84 #'(lambda (object)
85 (declare (ignore object))
308bfcab 86 (error "Slot is not readable: ~A" (slot-definition-name slotd)))
eeda1c2d 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
12b7df04 102 (setq reader
103 (mkbinding getter
104 (slot-definition-type slotd) 'pointer)))
09f6e237 105 (funcall reader (foreign-location object))))))))))
eeda1c2d 106
4d83a8a6 107 (setf
eeda1c2d 108 (slot-value slotd 'boundp-function)
109 (cond
eeda1c2d 110 ((slot-boundp slotd 'unbound)
111 (let ((unbound-value (slot-value slotd 'unbound)))
12b7df04 112 #'(lambda (object)
113 (not (eq (funcall getter-function object) unbound-value)))))
114 ((slot-boundp slotd 'boundp)
115 (let ((boundp (slot-value slotd 'boundp)))
eeda1c2d 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)))
09f6e237 126 (funcall reader (foreign-location object))))))))
75689fea 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)))))))
12b7df04 135 (#'(lambda (object) (declare (ignore object)) t))))
eeda1c2d 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)))
12b7df04 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)))))
eeda1c2d 148 ((slot-boundp slotd 'boundp)
149 (let ((boundp-function (slot-value slotd 'boundp-function)))
12b7df04 150 #'(lambda (object)
151 (and
152 (funcall boundp-function object)
153 (funcall getter-function object)))))
75689fea 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)))
12b7df04 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)))))))
eeda1c2d 166 (getter-function)))))
167
168 (setf
169 (slot-value slotd 'writer-function)
170 (if (not (slot-boundp slotd 'setter))
308bfcab 171 #'(lambda (value object)
172 (declare (ignore value object))
173 (error "Slot is not writable: ~A" (slot-definition-name slotd)))
eeda1c2d 174 (with-slots (setter) slotd
4d83a8a6 175 (etypecase setter
176 (function setter)
eeda1c2d 177 ((or symbol cons)
178 #'(lambda (value object)
179 (funcall (fdefinition setter) value object)))
7d1ddc9e 180 (string
eeda1c2d 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))))
09f6e237 189 (funcall writer (foreign-location object) value)))))))))
eeda1c2d 190
65466e9c 191 #-sbcl>=0.9.8(initialize-internal-slot-gfs (slot-definition-name slotd)))
4d83a8a6 192
193
194
eeda1c2d 195(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
4d83a8a6 196 nil)
197
9adccb27 198(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
b19bbc94 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)))
46e84256 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)))
e1b96602 217 (unless (eq type *unbound-marker*)
218 (setf (getf initargs :type) type)))
b19bbc94 219 (nconc initargs (call-next-method))))
220 (direct-special-slot-definition
221 (append '(:special t) (call-next-method)))
222 (t (call-next-method))))
4d83a8a6 223
94f15c3c 224
94f15c3c 225(defmethod slot-value-using-class
9adccb27 226 ((class virtual-slots-class) (object standard-object)
94f15c3c 227 (slotd effective-virtual-slot-definition))
4d83a8a6 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))))
94f15c3c 231
94f15c3c 232(defmethod slot-boundp-using-class
9adccb27 233 ((class virtual-slots-class) (object standard-object)
94f15c3c 234 (slotd effective-virtual-slot-definition))
4d83a8a6 235 (funcall (slot-value slotd 'boundp-function) object))
236
237(defmethod (setf slot-value-using-class)
9adccb27 238 (value (class virtual-slots-class) (object standard-object)
94f15c3c 239 (slotd effective-virtual-slot-definition))
4d83a8a6 240 (funcall (slot-value slotd 'writer-function) value object))
241
242
94f15c3c 243(defmethod validate-superclass
9adccb27 244 ((class virtual-slots-class) (super standard-class))
94f15c3c 245 t)
246
247
b19bbc94 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
94f15c3c 257;;;; Proxy cache
258
94f15c3c 259(defvar *instance-cache* (make-hash-table :test #'eql))
260
982a215a 261(defun cache-instance (instance &optional (weak-ref t))
94f15c3c 262 (setf
09f6e237 263 (gethash (sap-int (foreign-location instance)) *instance-cache*)
982a215a 264 (if weak-ref
265 (make-weak-pointer instance)
266 instance)))
94f15c3c 267
268(defun find-cached-instance (location)
73572c12 269 (let ((ref (gethash (sap-int location) *instance-cache*)))
94f15c3c 270 (when ref
982a215a 271 (if (weak-pointer-p ref)
272 (weak-pointer-value ref)
273 ref))))
94f15c3c 274
0f134a29 275(defun instance-cached-p (location)
73572c12 276 (gethash (sap-int location) *instance-cache*))
0f134a29 277
94f15c3c 278(defun remove-cached-instance (location)
73572c12 279 (remhash (sap-int location) *instance-cache*))
94f15c3c 280
9adccb27 281;; For debuging
982a215a 282(defun list-cached-instances ()
9adccb27 283 (let ((instances ()))
284 (maphash #'(lambda (location ref)
285 (declare (ignore location))
982a215a 286 (push ref instances))
9adccb27 287 *instance-cache*)
288 instances))
289
ca01de1b 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
94f15c3c 311
312
313;;;; Proxy for alien instances
314
4a64c16d 315;; TODO: add a ref-counted-proxy subclass
9adccb27 316(defclass proxy ()
b19bbc94 317 ((location :special t :type pointer))
e2ebafb1 318 (:metaclass virtual-slots-class))
94f15c3c 319
9adccb27 320(defgeneric instance-finalizer (object))
321(defgeneric reference-foreign (class location))
322(defgeneric unreference-foreign (class location))
4a64c16d 323(defgeneric invalidate-instance (object))
308bfcab 324(defgeneric allocate-foreign (object &key &allow-other-keys))
9adccb27 325
c0e19882 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
3b167652 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
9adccb27 341(defmethod unreference-foreign :around ((class class) location)
342 (unless (null-pointer-p location)
09f6e237 343 (call-next-method)))
94f15c3c 344
0f134a29 345(defmethod print-object ((instance proxy) stream)
346 (print-unreadable-object (instance stream :type t :identity nil)
09f6e237 347 (if (slot-boundp instance 'location)
348 (format stream "at 0x~X" (sap-int (foreign-location instance)))
75689fea 349 (write-string "at <unbound>" stream))))
94f15c3c 350
308bfcab 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))
8958fa4a 355 (prog1
356 (call-next-method)
357 (cache-instance instance)
358 (finalize instance (instance-finalizer instance))))
94f15c3c 359
360(defmethod instance-finalizer ((instance proxy))
09f6e237 361 (let ((location (foreign-location instance))
9adccb27 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 ()
1dbf4216 366 (remove-cached-instance location)
9adccb27 367 (unreference-foreign class location))))
12d0437e 368
ca01de1b 369;; Any reference to the foreign object the instance may have held
370;; should be released before this method is invoked
4a64c16d 371(defmethod invalidate-instance ((instance proxy))
372 (remove-cached-instance (foreign-location instance))
ca01de1b 373 (slot-makunbound instance 'location)
374 (cancel-finalization instance)
375 (cache-invalidated-instance instance))
4a64c16d 376
94f15c3c 377
378;;;; Metaclass used for subclasses of proxy
379
73572c12 380(defgeneric most-specific-proxy-superclass (class))
381(defgeneric direct-proxy-superclass (class))
382
383
94f15c3c 384(eval-when (:compile-toplevel :load-toplevel :execute)
9adccb27 385 (defclass proxy-class (virtual-slots-class)
09f6e237 386 ((size :reader foreign-size)))
94f15c3c 387
388 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
b19bbc94 389 ((offset :reader slot-definition-offset :initarg :offset))
390 (:default-initargs :allocation :alien))
94f15c3c 391
392 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
4d83a8a6 393 ((offset :reader slot-definition-offset :initarg :offset)))
12d0437e 394
94f15c3c 395 (defmethod most-specific-proxy-superclass ((class proxy-class))
396 (find-if
397 #'(lambda (class)
398 (subtypep (class-name class) 'proxy))
4d83a8a6 399 (cdr (compute-class-precedence-list class))))
73572c12 400
12d0437e 401 (defmethod direct-proxy-superclass ((class proxy-class))
402 (find-if
403 #'(lambda (class)
404 (subtypep (class-name class) 'proxy))
4d83a8a6 405 (class-direct-superclasses class)))
406
eeda1c2d 407 (defmethod shared-initialize ((class proxy-class) names &key size)
94f15c3c 408 (call-next-method)
12d0437e 409 (cond
4d83a8a6 410 (size (setf (slot-value class 'size) (first size)))
9adccb27 411 ((slot-boundp class 'size) (slot-makunbound class 'size))))
09f6e237 412
4d83a8a6 413 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 414 (case (getf initargs :allocation)
e2ebafb1 415 (:alien (find-class 'direct-alien-slot-definition))
94f15c3c 416 (t (call-next-method))))
4d83a8a6 417
418 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 419 (case (getf initargs :allocation)
420 (:alien (find-class 'effective-alien-slot-definition))
94f15c3c 421 (t (call-next-method))))
422
4d83a8a6 423
424 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
b19bbc94 425 (if (eq (slot-definition-allocation (first direct-slotds)) :alien)
4d83a8a6 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
9adccb27 434 (let ((type (slot-definition-type slotd)))
eeda1c2d 435 (unless (slot-boundp slotd 'getter)
9adccb27 436 (let ((reader (reader-function type)))
437 (setf
eeda1c2d 438 (slot-value slotd 'getter)
9adccb27 439 #'(lambda (object)
09f6e237 440 (funcall reader (foreign-location object) offset)))))
4d83a8a6 441
eeda1c2d 442 (unless (slot-boundp slotd 'setter)
9adccb27 443 (let ((writer (writer-function type))
444 (destroy (destroy-function type)))
445 (setf
eeda1c2d 446 (slot-value slotd 'setter)
9adccb27 447 #'(lambda (value object)
09f6e237 448 (let ((location (foreign-location object)))
9adccb27 449 (funcall destroy location offset) ; destroy old value
eeda1c2d 450 (funcall writer value location offset))))))))
451
4d83a8a6 452 (call-next-method))
453
42e68ad2 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)
94f15c3c 460
09f6e237 461 (defun align-offset (size)
462 (if (zerop (mod size +struct-alignmen+))
463 size
464 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
465
94f15c3c 466 (defmethod compute-slots ((class proxy-class))
09f6e237 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))))
94f15c3c 483 (call-next-method))
3e15002d 484
4d83a8a6 485 (defmethod validate-superclass ((class proxy-class) (super standard-class))
486 (subtypep (class-name super) 'proxy))
487
09f6e237 488 (defmethod foreign-size ((class-name symbol))
489 (foreign-size (find-class class-name))))
47a11c16 490
09f6e237 491(defmethod foreign-size ((object proxy))
492 (foreign-size (class-of object)))
4d83a8a6 493
09f6e237 494
75689fea 495(define-type-method alien-type ((class proxy))
496 (declare (ignore class))
9adccb27 497 (alien-type 'pointer))
498
75689fea 499(define-type-method size-of ((class proxy))
500 (declare (ignore class))
9adccb27 501 (size-of 'pointer))
502
75689fea 503(define-type-method from-alien-form ((type proxy) location)
504 (let ((class (type-expand type)))
505 `(ensure-proxy-instance ',class ,location)))
9adccb27 506
75689fea 507(define-type-method from-alien-function ((type proxy))
508 (let ((class (type-expand type)))
509 #'(lambda (location)
510 (ensure-proxy-instance class location))))
94f15c3c 511
75689fea 512(define-type-method to-alien-form ((type proxy) instance)
513 (declare (ignore type))
09f6e237 514 `(foreign-location ,instance))
94f15c3c 515
75689fea 516(define-type-method to-alien-function ((type proxy))
517 (declare (ignore type))
09f6e237 518 #'foreign-location)
9adccb27 519
75689fea 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)
9adccb27 562
8958fa4a 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."
9adccb27 567 (unless (null-pointer-p location)
568 (or
aaced14e 569 #-debug-ref-counting(find-cached-instance location)
570 #+debug-ref-counting
4a64c16d 571 (let ((instance (find-cached-instance location)))
572 (when instance
573 (format t "Object found in cache: ~A~%" instance)
574 instance))
8958fa4a 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
4a64c16d 584(defmethod make-proxy-instance ((class symbol) location &rest initargs)
585 (apply #'make-proxy-instance (find-class class) location initargs))
8958fa4a 586
587(defmethod make-proxy-instance ((class proxy-class) location &key weak)
ca01de1b 588 (let ((instance
589 (or
590 (find-invalidated-instance class)
591 (allocate-instance class))))
c0e19882 592 (setf (foreign-location instance) location)
8958fa4a 593 (unless weak
594 (finalize instance (instance-finalizer instance)))
595 instance))
94f15c3c 596
12d0437e 597
598;;;; Superclasses for wrapping of C structures
94f15c3c 599
9adccb27 600(defclass struct (proxy)
601 ()
09f6e237 602 (:metaclass proxy-class)
603 (:size 0))
94f15c3c 604
308bfcab 605(defmethod allocate-foreign ((struct struct) &rest initargs)
94f15c3c 606 (declare (ignore initargs))
308bfcab 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))))
94f15c3c 611
612
9adccb27 613;;;; Metaclasses used for subclasses of struct
614
75689fea 615(eval-when (:compile-toplevel :load-toplevel :execute)
616 (defclass struct-class (proxy-class)
617 ()))
94f15c3c 618
e2ebafb1 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
9adccb27 624(defmethod reference-foreign ((class struct-class) location)
09f6e237 625 (copy-memory location (foreign-size class)))
9adccb27 626
627(defmethod unreference-foreign ((class struct-class) location)
12d0437e 628 (deallocate-memory location))
94f15c3c 629
65466e9c 630(defmethod compute-slots :around ((class struct-class))
631 (let ((slots (call-next-method)))
632 (when (and
b19bbc94 633 #-sbcl>=0.9.8(class-finalized-p class)
65466e9c 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))
09f6e237 643
75689fea 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))))))))
4a64c16d 660
94f15c3c 661
9adccb27 662(defclass static-struct-class (struct-class)
663 ())
94f15c3c 664
9adccb27 665(defmethod reference-foreign ((class static-struct-class) location)
666 (declare (ignore class))
12d0437e 667 location)
94f15c3c 668
9adccb27 669(defmethod unreference-foreign ((class static-struct-class) location)
670 (declare (ignore class location))
12d0437e 671 nil)
bde0b906 672
bde0b906 673;;; Pseudo type for structs which are inlined in other objects
674
75689fea 675(deftype inlined (type) type)
bde0b906 676
75689fea 677(define-type-method size-of ((type inlined))
58ed7439 678 (let ((class (second (type-expand-to 'inlined type))))
75689fea 679 (foreign-size class)))
680
681(define-type-method reader-function ((type inlined))
58ed7439 682 (let ((class (second (type-expand-to 'inlined type))))
3005806e 683 #'(lambda (location &optional (offset 0) weak-p)
684 (declare (ignore weak-p))
bde0b906 685 (ensure-proxy-instance class
686 (reference-foreign class (sap+ location offset))))))
687
75689fea 688(define-type-method writer-function ((type inlined))
58ed7439 689 (let ((class (second (type-expand-to 'inlined type))))
4a64c16d 690 #'(lambda (instance location &optional (offset 0))
691 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
692
58ed7439 693(define-type-method destroy-function ((type inlined))
694 (declare (ignore type))
695 #'(lambda (location &optional offset)
696 (declare (ignore location offset))))
697
698
bde0b906 699(export 'inlined)