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