chiark / gitweb /
Amd64 port marked as done, added CLisp port as task to be done
[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
42e68ad2 23;; $Id: proxy.lisp,v 1.37 2006-02-26 16:12:25 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)))
e1b96602 214 ;; Need this to prevent type expansion in SBCL >= 0.9.8
215 (let ((type (most-specific-slot-value direct-slotds 'type)))
216 (unless (eq type *unbound-marker*)
217 (setf (getf initargs :type) type)))
b19bbc94 218 (nconc initargs (call-next-method))))
219 (direct-special-slot-definition
220 (append '(:special t) (call-next-method)))
221 (t (call-next-method))))
4d83a8a6 222
94f15c3c 223
94f15c3c 224(defmethod slot-value-using-class
9adccb27 225 ((class virtual-slots-class) (object standard-object)
94f15c3c 226 (slotd effective-virtual-slot-definition))
4d83a8a6 227 (if (funcall (slot-value slotd 'boundp-function) object)
228 (funcall (slot-value slotd 'reader-function) object)
229 (slot-unbound class object (slot-definition-name slotd))))
94f15c3c 230
94f15c3c 231(defmethod slot-boundp-using-class
9adccb27 232 ((class virtual-slots-class) (object standard-object)
94f15c3c 233 (slotd effective-virtual-slot-definition))
4d83a8a6 234 (funcall (slot-value slotd 'boundp-function) object))
235
236(defmethod (setf slot-value-using-class)
9adccb27 237 (value (class virtual-slots-class) (object standard-object)
94f15c3c 238 (slotd effective-virtual-slot-definition))
4d83a8a6 239 (funcall (slot-value slotd 'writer-function) value object))
240
241
94f15c3c 242(defmethod validate-superclass
9adccb27 243 ((class virtual-slots-class) (super standard-class))
94f15c3c 244 t)
245
246
b19bbc94 247(defmethod slot-definition-special ((slotd standard-direct-slot-definition))
248 (declare (ignore slotd))
249 nil)
250
251(defmethod slot-definition-special ((slotd standard-effective-slot-definition))
252 (declare (ignore slotd))
253 nil)
254
255
94f15c3c 256;;;; Proxy cache
257
94f15c3c 258(defvar *instance-cache* (make-hash-table :test #'eql))
259
982a215a 260(defun cache-instance (instance &optional (weak-ref t))
94f15c3c 261 (setf
09f6e237 262 (gethash (sap-int (foreign-location instance)) *instance-cache*)
982a215a 263 (if weak-ref
264 (make-weak-pointer instance)
265 instance)))
94f15c3c 266
267(defun find-cached-instance (location)
73572c12 268 (let ((ref (gethash (sap-int location) *instance-cache*)))
94f15c3c 269 (when ref
982a215a 270 (if (weak-pointer-p ref)
271 (weak-pointer-value ref)
272 ref))))
94f15c3c 273
0f134a29 274(defun instance-cached-p (location)
73572c12 275 (gethash (sap-int location) *instance-cache*))
0f134a29 276
94f15c3c 277(defun remove-cached-instance (location)
73572c12 278 (remhash (sap-int location) *instance-cache*))
94f15c3c 279
9adccb27 280;; For debuging
982a215a 281(defun list-cached-instances ()
9adccb27 282 (let ((instances ()))
283 (maphash #'(lambda (location ref)
284 (declare (ignore location))
982a215a 285 (push ref instances))
9adccb27 286 *instance-cache*)
287 instances))
288
ca01de1b 289;; Instances that gets invalidated tend to be short lived, but created
290;; in large numbers. So we're keeping them in a hash table to be able
291;; to reuse them (and thus reduce consing)
292(defvar *invalidated-instance-cache* (make-hash-table :test #'eql))
293
294(defun cache-invalidated-instance (instance)
295 (push instance
296 (gethash (class-of instance) *invalidated-instance-cache*)))
297
298(defun find-invalidated-instance (class)
299 (when (gethash class *invalidated-instance-cache*)
300 (pop (gethash class *invalidated-instance-cache*))))
301
302(defun list-invalidated-instances ()
303 (let ((instances ()))
304 (maphash #'(lambda (location ref)
305 (declare (ignore location))
306 (push ref instances))
307 *invalidated-instance-cache*)
308 instances))
309
94f15c3c 310
311
312;;;; Proxy for alien instances
313
4a64c16d 314;; TODO: add a ref-counted-proxy subclass
9adccb27 315(defclass proxy ()
b19bbc94 316 ((location :special t :type pointer))
e2ebafb1 317 (:metaclass virtual-slots-class))
94f15c3c 318
9adccb27 319(defgeneric instance-finalizer (object))
320(defgeneric reference-foreign (class location))
321(defgeneric unreference-foreign (class location))
4a64c16d 322(defgeneric invalidate-instance (object))
308bfcab 323(defgeneric allocate-foreign (object &key &allow-other-keys))
9adccb27 324
c0e19882 325(defun foreign-location (instance)
326 (slot-value instance 'location))
327
328(defun (setf foreign-location) (location instance)
329 (setf (slot-value instance 'location) location))
330
331(defun proxy-valid-p (instance)
332 (slot-boundp instance 'location))
333
3b167652 334(defmethod reference-foreign ((name symbol) location)
335 (reference-foreign (find-class name) location))
336
337(defmethod unreference-foreign ((name symbol) location)
338 (unreference-foreign (find-class name) location))
339
9adccb27 340(defmethod unreference-foreign :around ((class class) location)
341 (unless (null-pointer-p location)
09f6e237 342 (call-next-method)))
94f15c3c 343
0f134a29 344(defmethod print-object ((instance proxy) stream)
345 (print-unreadable-object (instance stream :type t :identity nil)
09f6e237 346 (if (slot-boundp instance 'location)
347 (format stream "at 0x~X" (sap-int (foreign-location instance)))
75689fea 348 (write-string "at <unbound>" stream))))
94f15c3c 349
308bfcab 350(defmethod initialize-instance :around ((instance proxy) &rest initargs &key &allow-other-keys)
351 (setf
352 (foreign-location instance)
353 (apply #'allocate-foreign instance initargs))
8958fa4a 354 (prog1
355 (call-next-method)
356 (cache-instance instance)
357 (finalize instance (instance-finalizer instance))))
94f15c3c 358
359(defmethod instance-finalizer ((instance proxy))
09f6e237 360 (let ((location (foreign-location instance))
9adccb27 361 (class (class-of instance)))
362;; (unless (find-method #'unreference-foreign nil (list (class-of class) t) nil)
363;; (error "No matching method for UNREFERENCE-INSTANCE when called with class ~A" class))
364 #'(lambda ()
1dbf4216 365 (remove-cached-instance location)
9adccb27 366 (unreference-foreign class location))))
12d0437e 367
ca01de1b 368;; Any reference to the foreign object the instance may have held
369;; should be released before this method is invoked
4a64c16d 370(defmethod invalidate-instance ((instance proxy))
371 (remove-cached-instance (foreign-location instance))
ca01de1b 372 (slot-makunbound instance 'location)
373 (cancel-finalization instance)
374 (cache-invalidated-instance instance))
4a64c16d 375
94f15c3c 376
377;;;; Metaclass used for subclasses of proxy
378
73572c12 379(defgeneric most-specific-proxy-superclass (class))
380(defgeneric direct-proxy-superclass (class))
381
382
94f15c3c 383(eval-when (:compile-toplevel :load-toplevel :execute)
9adccb27 384 (defclass proxy-class (virtual-slots-class)
09f6e237 385 ((size :reader foreign-size)))
94f15c3c 386
387 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
b19bbc94 388 ((offset :reader slot-definition-offset :initarg :offset))
389 (:default-initargs :allocation :alien))
94f15c3c 390
391 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
4d83a8a6 392 ((offset :reader slot-definition-offset :initarg :offset)))
12d0437e 393
94f15c3c 394 (defmethod most-specific-proxy-superclass ((class proxy-class))
395 (find-if
396 #'(lambda (class)
397 (subtypep (class-name class) 'proxy))
4d83a8a6 398 (cdr (compute-class-precedence-list class))))
73572c12 399
12d0437e 400 (defmethod direct-proxy-superclass ((class proxy-class))
401 (find-if
402 #'(lambda (class)
403 (subtypep (class-name class) 'proxy))
4d83a8a6 404 (class-direct-superclasses class)))
405
eeda1c2d 406 (defmethod shared-initialize ((class proxy-class) names &key size)
94f15c3c 407 (call-next-method)
12d0437e 408 (cond
4d83a8a6 409 (size (setf (slot-value class 'size) (first size)))
9adccb27 410 ((slot-boundp class 'size) (slot-makunbound class 'size))))
09f6e237 411
4d83a8a6 412 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 413 (case (getf initargs :allocation)
e2ebafb1 414 (:alien (find-class 'direct-alien-slot-definition))
94f15c3c 415 (t (call-next-method))))
4d83a8a6 416
417 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 418 (case (getf initargs :allocation)
419 (:alien (find-class 'effective-alien-slot-definition))
94f15c3c 420 (t (call-next-method))))
421
4d83a8a6 422
423 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
b19bbc94 424 (if (eq (slot-definition-allocation (first direct-slotds)) :alien)
4d83a8a6 425 (nconc
426 (list :offset (most-specific-slot-value direct-slotds 'offset))
427 (call-next-method))
428 (call-next-method)))
429
430
431 (defmethod initialize-internal-slot-functions ((slotd effective-alien-slot-definition))
432 (with-slots (offset) slotd
9adccb27 433 (let ((type (slot-definition-type slotd)))
eeda1c2d 434 (unless (slot-boundp slotd 'getter)
9adccb27 435 (let ((reader (reader-function type)))
436 (setf
eeda1c2d 437 (slot-value slotd 'getter)
9adccb27 438 #'(lambda (object)
09f6e237 439 (funcall reader (foreign-location object) offset)))))
4d83a8a6 440
eeda1c2d 441 (unless (slot-boundp slotd 'setter)
9adccb27 442 (let ((writer (writer-function type))
443 (destroy (destroy-function type)))
444 (setf
eeda1c2d 445 (slot-value slotd 'setter)
9adccb27 446 #'(lambda (value object)
09f6e237 447 (let ((location (foreign-location object)))
9adccb27 448 (funcall destroy location offset) ; destroy old value
eeda1c2d 449 (funcall writer value location offset))))))))
450
4d83a8a6 451 (call-next-method))
452
42e68ad2 453 (defconstant +struct-alignmen+
454 #+sbcl (/ (sb-alien-internals:alien-type-alignment
455 (sb-alien-internals:parse-alien-type
456 'system-area-pointer nil))
457 8)
458 #-sbcl 4)
94f15c3c 459
09f6e237 460 (defun align-offset (size)
461 (if (zerop (mod size +struct-alignmen+))
462 size
463 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
464
94f15c3c 465 (defmethod compute-slots ((class proxy-class))
09f6e237 466 (let ((alien-slots
467 (remove-if-not
468 #'(lambda (slotd)
469 (eq (slot-definition-allocation slotd) :alien))
470 (class-direct-slots class))))
471 (when alien-slots
472 (loop
473 as offset = (align-offset (foreign-size
474 (most-specific-proxy-superclass class)))
475 then (align-offset
476 (+
477 (slot-definition-offset slotd)
478 (size-of (slot-definition-type slotd))))
479 for slotd in alien-slots
480 unless (slot-boundp slotd 'offset)
481 do (setf (slot-value slotd 'offset) offset))))
94f15c3c 482 (call-next-method))
3e15002d 483
4d83a8a6 484 (defmethod validate-superclass ((class proxy-class) (super standard-class))
485 (subtypep (class-name super) 'proxy))
486
09f6e237 487 (defmethod foreign-size ((class-name symbol))
488 (foreign-size (find-class class-name))))
47a11c16 489
09f6e237 490(defmethod foreign-size ((object proxy))
491 (foreign-size (class-of object)))
4d83a8a6 492
09f6e237 493
75689fea 494(define-type-method alien-type ((class proxy))
495 (declare (ignore class))
9adccb27 496 (alien-type 'pointer))
497
75689fea 498(define-type-method size-of ((class proxy))
499 (declare (ignore class))
9adccb27 500 (size-of 'pointer))
501
75689fea 502(define-type-method from-alien-form ((type proxy) location)
503 (let ((class (type-expand type)))
504 `(ensure-proxy-instance ',class ,location)))
9adccb27 505
75689fea 506(define-type-method from-alien-function ((type proxy))
507 (let ((class (type-expand type)))
508 #'(lambda (location)
509 (ensure-proxy-instance class location))))
94f15c3c 510
75689fea 511(define-type-method to-alien-form ((type proxy) instance)
512 (declare (ignore type))
09f6e237 513 `(foreign-location ,instance))
94f15c3c 514
75689fea 515(define-type-method to-alien-function ((type proxy))
516 (declare (ignore type))
09f6e237 517 #'foreign-location)
9adccb27 518
75689fea 519(define-type-method copy-from-alien-form ((type proxy) location)
520 (let ((class (type-expand type)))
521 `(ensure-proxy-instance ',class (reference-foreign ',class ,location))))
522
523(define-type-method copy-from-alien-function ((type proxy))
524 (let ((class (type-expand type)))
525 #'(lambda (location)
526 (ensure-proxy-instance class (reference-foreign class location)))))
527
528(define-type-method copy-to-alien-form ((type proxy) instance)
529 (let ((class (type-expand type)))
530 `(reference-foreign ',class (foreign-location ,instance))))
531
532(define-type-method copy-to-alien-function ((type proxy))
533 (let ((class (type-expand type)))
534 #'(lambda (instance)
535 (reference-foreign class (foreign-location instance)))))
536
537(define-type-method writer-function ((type proxy))
538 (let ((class (type-expand type)))
539 #'(lambda (instance location &optional (offset 0))
540 (assert (null-pointer-p (sap-ref-sap location offset)))
541 (setf
542 (sap-ref-sap location offset)
543 (reference-foreign class (foreign-location instance))))))
544
545(define-type-method reader-function ((type proxy))
546 (let ((class (type-expand type)))
547 #'(lambda (location &optional (offset 0) weak-p)
548 (declare (ignore weak-p))
549 (let ((instance (sap-ref-sap location offset)))
550 (unless (null-pointer-p instance)
551 (ensure-proxy-instance class (reference-foreign class instance)))))))
552
553(define-type-method destroy-function ((type proxy))
554 (let ((class (type-expand type)))
555 #'(lambda (location &optional (offset 0))
556 (unreference-foreign class (sap-ref-sap location offset)))))
557
558(define-type-method unbound-value ((type proxy))
559 (declare (ignore type))
560 nil)
9adccb27 561
8958fa4a 562(defun ensure-proxy-instance (class location &rest initargs)
563 "Returns a proxy object representing the foreign object at the give
564location. If an existing object is not found in the cache
565MAKE-PROXY-INSTANCE is called to create one."
9adccb27 566 (unless (null-pointer-p location)
567 (or
aaced14e 568 #-debug-ref-counting(find-cached-instance location)
569 #+debug-ref-counting
4a64c16d 570 (let ((instance (find-cached-instance location)))
571 (when instance
572 (format t "Object found in cache: ~A~%" instance)
573 instance))
8958fa4a 574 (let ((instance (apply #'make-proxy-instance class location initargs)))
575 (cache-instance instance)
576 instance))))
577
578(defgeneric make-proxy-instance (class location &key weak)
579 (:documentation "Creates a new proxy object representing the foreign
580object at the give location. If WEAK is non NIL the foreign memory
581will not be released when the proxy is garbage collected."))
582
4a64c16d 583(defmethod make-proxy-instance ((class symbol) location &rest initargs)
584 (apply #'make-proxy-instance (find-class class) location initargs))
8958fa4a 585
586(defmethod make-proxy-instance ((class proxy-class) location &key weak)
ca01de1b 587 (let ((instance
588 (or
589 (find-invalidated-instance class)
590 (allocate-instance class))))
c0e19882 591 (setf (foreign-location instance) location)
8958fa4a 592 (unless weak
593 (finalize instance (instance-finalizer instance)))
594 instance))
94f15c3c 595
12d0437e 596
597;;;; Superclasses for wrapping of C structures
94f15c3c 598
9adccb27 599(defclass struct (proxy)
600 ()
09f6e237 601 (:metaclass proxy-class)
602 (:size 0))
94f15c3c 603
308bfcab 604(defmethod allocate-foreign ((struct struct) &rest initargs)
94f15c3c 605 (declare (ignore initargs))
308bfcab 606 (let ((size (foreign-size (class-of struct))))
607 (if (zerop size)
608 (error "~A has zero size" (class-of struct))
609 (allocate-memory size))))
94f15c3c 610
611
9adccb27 612;;;; Metaclasses used for subclasses of struct
613
75689fea 614(eval-when (:compile-toplevel :load-toplevel :execute)
615 (defclass struct-class (proxy-class)
616 ()))
94f15c3c 617
e2ebafb1 618(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
619 (if (not (getf initargs :allocation))
620 (find-class 'direct-alien-slot-definition)
621 (call-next-method)))
622
9adccb27 623(defmethod reference-foreign ((class struct-class) location)
09f6e237 624 (copy-memory location (foreign-size class)))
9adccb27 625
626(defmethod unreference-foreign ((class struct-class) location)
12d0437e 627 (deallocate-memory location))
94f15c3c 628
65466e9c 629(defmethod compute-slots :around ((class struct-class))
630 (let ((slots (call-next-method)))
631 (when (and
b19bbc94 632 #-sbcl>=0.9.8(class-finalized-p class)
65466e9c 633 (not (slot-boundp class 'size)))
634 (let ((size (loop
635 for slotd in slots
636 when (eq (slot-definition-allocation slotd) :alien)
637 maximize (+
638 (slot-definition-offset slotd)
639 (size-of (slot-definition-type slotd))))))
640 (setf (slot-value class 'size) (+ size (mod size +struct-alignmen+)))))
641 slots))
09f6e237 642
75689fea 643(define-type-method callback-from-alien-form ((type struct) form)
644 (let ((class (type-expand type)))
645 `(ensure-proxy-instance ',class ,form :weak t)))
646
647(define-type-method callback-cleanup-form ((type struct) form)
648 (declare (ignore type))
649 `(invalidate-instance ,form))
650
651(define-type-method reader-function ((type struct))
652 (let ((class (type-expand type)))
653 #'(lambda (location &optional (offset 0) weak-p)
654 (let ((instance (sap-ref-sap location offset)))
655 (unless (null-pointer-p instance)
656 (if weak-p
657 (ensure-proxy-instance class instance :weak t)
658 (ensure-proxy-instance class (reference-foreign class instance))))))))
4a64c16d 659
94f15c3c 660
9adccb27 661(defclass static-struct-class (struct-class)
662 ())
94f15c3c 663
9adccb27 664(defmethod reference-foreign ((class static-struct-class) location)
665 (declare (ignore class))
12d0437e 666 location)
94f15c3c 667
9adccb27 668(defmethod unreference-foreign ((class static-struct-class) location)
669 (declare (ignore class location))
12d0437e 670 nil)
bde0b906 671
bde0b906 672;;; Pseudo type for structs which are inlined in other objects
673
75689fea 674(deftype inlined (type) type)
bde0b906 675
75689fea 676(define-type-method size-of ((type inlined))
677 (let ((class (type-expand (second type))))
678 (foreign-size class)))
679
680(define-type-method reader-function ((type inlined))
681 (let ((class (type-expand (second type))))
3005806e 682 #'(lambda (location &optional (offset 0) weak-p)
683 (declare (ignore weak-p))
bde0b906 684 (ensure-proxy-instance class
685 (reference-foreign class (sap+ location offset))))))
686
75689fea 687(define-type-method writer-function ((type inlined))
688 (let ((class (type-expand (second type))))
4a64c16d 689 #'(lambda (instance location &optional (offset 0))
690 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
691
bde0b906 692(export 'inlined)