chiark / gitweb /
Proxies may now have "weak" references to the foreign object
[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
253c1339 23;; $Id: proxy.lisp,v 1.26 2006/02/06 11:52:24 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)
46 ())
b44caf77 47
82defe4d 48 (defclass effective-special-slot-definition (standard-effective-slot-definition)
49 ()))
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
62(defmethod initialize-instance ((slotd effective-special-slot-definition) &rest initargs)
63 (declare (ignore initargs))
64 (call-next-method)
65 (setf (slot-value slotd 'allocation) :instance))
66
b44caf77 67
6baf860c 68(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
82defe4d 69 (case (getf initargs :allocation)
70 (:virtual (find-class 'direct-virtual-slot-definition))
71 (:special (find-class 'direct-special-slot-definition))
72 (t (call-next-method))))
b44caf77 73
6baf860c 74(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
82defe4d 75 (case (getf initargs :allocation)
76 (:virtual (find-class 'effective-virtual-slot-definition))
77 (:special (find-class 'effective-special-slot-definition))
78 (t (call-next-method))))
b44caf77 79
935a783c 80
81(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
64bce834 82 (if (not (slot-boundp slotd 'getter))
83 (setf
935a783c 84 (slot-value slotd 'reader-function)
64bce834 85 #'(lambda (object)
86 (declare (ignore object))
87 (error "Can't read slot: ~A" (slot-definition-name slotd)))
88 (slot-value slotd 'boundp-function)
89 #'(lambda (object) (declare (ignore object)) nil))
90
91 (let ((getter-function
92 (let ((getter (slot-value slotd 'getter)))
93 (etypecase getter
94 (function getter)
95 (symbol
96 #'(lambda (object)
97 (funcall getter object)))
98 (string
99 (let ((reader nil))
100 (setf (slot-value slotd 'reader-function)
101 #'(lambda (object)
102 (unless reader
b6bf802c 103 (setq reader
104 (mkbinding getter
105 (slot-definition-type slotd) 'pointer)))
7ce0497d 106 (funcall reader (foreign-location object))))))))))
64bce834 107
935a783c 108 (setf
64bce834 109 (slot-value slotd 'boundp-function)
110 (cond
64bce834 111 ((slot-boundp slotd 'unbound)
112 (let ((unbound-value (slot-value slotd 'unbound)))
b6bf802c 113 #'(lambda (object)
114 (not (eq (funcall getter-function object) unbound-value)))))
115 ((slot-boundp slotd 'boundp)
116 (let ((boundp (slot-value slotd 'boundp)))
64bce834 117 (etypecase boundp
118 (function boundp)
119 (symbol #'(lambda (object)
120 (funcall boundp object)))
121 (string (let ((reader ()))
122 #'(lambda (object)
123 (unless reader
124 (setq reader
125 (mkbinding boundp
126 (slot-definition-type slotd) 'pointer)))
7ce0497d 127 (funcall reader (foreign-location object))))))))
b6bf802c 128 ((multiple-value-bind (unbound-p unbound-value)
129 (unbound-value (slot-definition-type slotd))
130 (when unbound-p
131 #'(lambda (object)
132 (not (eq (funcall getter-function object) unbound-value))))))
133 (#'(lambda (object) (declare (ignore object)) t))))
64bce834 134
135 (setf
136 (slot-value slotd 'reader-function)
137 (cond
138 ((slot-boundp slotd 'unbound)
139 (let ((unbound (slot-value slotd 'unbound))
140 (slot-name (slot-definition-name slotd)))
b6bf802c 141 #'(lambda (object)
142 (let ((value (funcall getter-function object)))
143 (if (eq value unbound)
144 (slot-unbound (class-of object) object slot-name)
145 value)))))
64bce834 146 ((slot-boundp slotd 'boundp)
147 (let ((boundp-function (slot-value slotd 'boundp-function)))
b6bf802c 148 #'(lambda (object)
149 (and
150 (funcall boundp-function object)
151 (funcall getter-function object)))))
152 ((multiple-value-bind (unbound-p unbound-value)
153 (unbound-value (slot-definition-type slotd))
154 (let ((slot-name (slot-definition-name slotd)))
155 (when unbound-p
156 #'(lambda (object)
157 (let ((value (funcall getter-function object)))
158 (if (eq value unbound-value)
159 (slot-unbound (class-of object) object slot-name)
160 value)))))))
64bce834 161 (getter-function)))))
162
163 (setf
164 (slot-value slotd 'writer-function)
165 (if (not (slot-boundp slotd 'setter))
166 #'(lambda (object)
167 (declare (ignore object))
168 (error "Can't set slot: ~A" (slot-definition-name slotd)))
169 (with-slots (setter) slotd
935a783c 170 (etypecase setter
171 (function setter)
64bce834 172 ((or symbol cons)
173 #'(lambda (value object)
174 (funcall (fdefinition setter) value object)))
0466f75e 175 (string
64bce834 176 (let ((writer ()))
177 (setf
178 (slot-value slotd 'writer-function)
179 #'(lambda (value object)
180 (unless writer
181 (setq writer
182 (mkbinding setter 'nil 'pointer
183 (slot-definition-type slotd))))
7ce0497d 184 (funcall writer (foreign-location object) value)))))))))
64bce834 185
935a783c 186 (initialize-internal-slot-gfs (slot-definition-name slotd)))
187
188
189
64bce834 190(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
935a783c 191 nil)
192
6baf860c 193(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
64bce834 194 (if (typep (first direct-slotds) '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)))
208 (nconc initargs (call-next-method)))
935a783c 209 (call-next-method)))
210
b44caf77 211
b44caf77 212(defmethod slot-value-using-class
6baf860c 213 ((class virtual-slots-class) (object standard-object)
b44caf77 214 (slotd effective-virtual-slot-definition))
935a783c 215 (if (funcall (slot-value slotd 'boundp-function) object)
216 (funcall (slot-value slotd 'reader-function) object)
217 (slot-unbound class object (slot-definition-name slotd))))
b44caf77 218
b44caf77 219(defmethod slot-boundp-using-class
6baf860c 220 ((class virtual-slots-class) (object standard-object)
b44caf77 221 (slotd effective-virtual-slot-definition))
935a783c 222 (funcall (slot-value slotd 'boundp-function) object))
223
224(defmethod (setf slot-value-using-class)
6baf860c 225 (value (class virtual-slots-class) (object standard-object)
b44caf77 226 (slotd effective-virtual-slot-definition))
935a783c 227 (funcall (slot-value slotd 'writer-function) value object))
228
229
b44caf77 230(defmethod validate-superclass
6baf860c 231 ((class virtual-slots-class) (super standard-class))
b44caf77 232 t)
233
234
235;;;; Proxy cache
236
237(internal *instance-cache*)
238(defvar *instance-cache* (make-hash-table :test #'eql))
239
a2bc0f3a 240(defun cache-instance (instance &optional (weak-ref t))
b44caf77 241 (setf
7ce0497d 242 (gethash (sap-int (foreign-location instance)) *instance-cache*)
a2bc0f3a 243 (if weak-ref
244 (make-weak-pointer instance)
245 instance)))
b44caf77 246
247(defun find-cached-instance (location)
3d36c5d6 248 (let ((ref (gethash (sap-int location) *instance-cache*)))
b44caf77 249 (when ref
a2bc0f3a 250 (if (weak-pointer-p ref)
251 (weak-pointer-value ref)
252 ref))))
b44caf77 253
a5c3a597 254(defun instance-cached-p (location)
3d36c5d6 255 (gethash (sap-int location) *instance-cache*))
a5c3a597 256
b44caf77 257(defun remove-cached-instance (location)
3d36c5d6 258 (remhash (sap-int location) *instance-cache*))
b44caf77 259
6baf860c 260;; For debuging
a2bc0f3a 261(defun list-cached-instances ()
6baf860c 262 (let ((instances ()))
263 (maphash #'(lambda (location ref)
264 (declare (ignore location))
a2bc0f3a 265 (push ref instances))
6baf860c 266 *instance-cache*)
267 instances))
268
b44caf77 269
270
271;;;; Proxy for alien instances
272
253c1339 273;; TODO: add a ref-counted-proxy subclass
6baf860c 274(defclass proxy ()
7ce0497d 275 ((location :allocation :special :reader foreign-location :type pointer))
82defe4d 276 (:metaclass virtual-slots-class))
b44caf77 277
6baf860c 278(defgeneric instance-finalizer (object))
279(defgeneric reference-foreign (class location))
280(defgeneric unreference-foreign (class location))
253c1339 281(defgeneric invalidate-instance (object))
6baf860c 282
c55abd76 283(defmethod reference-foreign ((name symbol) location)
284 (reference-foreign (find-class name) location))
285
286(defmethod unreference-foreign ((name symbol) location)
287 (unreference-foreign (find-class name) location))
288
6baf860c 289(defmethod unreference-foreign :around ((class class) location)
290 (unless (null-pointer-p location)
7ce0497d 291 (call-next-method)))
b44caf77 292
a5c3a597 293(defmethod print-object ((instance proxy) stream)
294 (print-unreadable-object (instance stream :type t :identity nil)
7ce0497d 295 (if (slot-boundp instance 'location)
296 (format stream "at 0x~X" (sap-int (foreign-location instance)))
297 (write-string "at \"unbound\"" stream))))
b44caf77 298
1d06a422 299(defmethod initialize-instance :around ((instance proxy) &rest initargs)
300 (declare (ignore initargs))
301 (prog1
302 (call-next-method)
303 (cache-instance instance)
304 (finalize instance (instance-finalizer instance))))
b44caf77 305
306(defmethod instance-finalizer ((instance proxy))
7ce0497d 307 (let ((location (foreign-location instance))
6baf860c 308 (class (class-of instance)))
309;; (unless (find-method #'unreference-foreign nil (list (class-of class) t) nil)
310;; (error "No matching method for UNREFERENCE-INSTANCE when called with class ~A" class))
311 #'(lambda ()
29933e83 312 (remove-cached-instance location)
6baf860c 313 (unreference-foreign class location))))
ba25fa44 314
253c1339 315(defmethod invalidate-instance ((instance proxy))
316 (remove-cached-instance (foreign-location instance))
317 (slot-makunbound instance 'location))
318
b44caf77 319
320;;;; Metaclass used for subclasses of proxy
321
3d36c5d6 322(defgeneric most-specific-proxy-superclass (class))
323(defgeneric direct-proxy-superclass (class))
7ce0497d 324(defgeneric compute-foreign-size (class))
3d36c5d6 325
326
b44caf77 327(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 328 (defclass proxy-class (virtual-slots-class)
7ce0497d 329 ((size :reader foreign-size)))
b44caf77 330
331 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
ba25fa44 332 ((allocation :initform :alien)
333 (offset :reader slot-definition-offset :initarg :offset)))
b44caf77 334
335 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
935a783c 336 ((offset :reader slot-definition-offset :initarg :offset)))
ba25fa44 337
b44caf77 338 (defmethod most-specific-proxy-superclass ((class proxy-class))
339 (find-if
340 #'(lambda (class)
341 (subtypep (class-name class) 'proxy))
935a783c 342 (cdr (compute-class-precedence-list class))))
3d36c5d6 343
ba25fa44 344 (defmethod direct-proxy-superclass ((class proxy-class))
345 (find-if
346 #'(lambda (class)
347 (subtypep (class-name class) 'proxy))
935a783c 348 (class-direct-superclasses class)))
349
64bce834 350 (defmethod shared-initialize ((class proxy-class) names &key size)
b44caf77 351 (call-next-method)
ba25fa44 352 (cond
935a783c 353 (size (setf (slot-value class 'size) (first size)))
6baf860c 354 ((slot-boundp class 'size) (slot-makunbound class 'size))))
7ce0497d 355
935a783c 356 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 357 (case (getf initargs :allocation)
82defe4d 358 (:alien (find-class 'direct-alien-slot-definition))
b44caf77 359 (t (call-next-method))))
935a783c 360
361 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 362 (case (getf initargs :allocation)
363 (:alien (find-class 'effective-alien-slot-definition))
b44caf77 364 (t (call-next-method))))
365
935a783c 366
367 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
368 (if (eq (most-specific-slot-value direct-slotds 'allocation) :alien)
369 (nconc
370 (list :offset (most-specific-slot-value direct-slotds 'offset))
371 (call-next-method))
372 (call-next-method)))
373
374
375 (defmethod initialize-internal-slot-functions ((slotd effective-alien-slot-definition))
376 (with-slots (offset) slotd
6baf860c 377 (let ((type (slot-definition-type slotd)))
64bce834 378 (unless (slot-boundp slotd 'getter)
6baf860c 379 (let ((reader (reader-function type)))
380 (setf
64bce834 381 (slot-value slotd 'getter)
6baf860c 382 #'(lambda (object)
7ce0497d 383 (funcall reader (foreign-location object) offset)))))
935a783c 384
64bce834 385 (unless (slot-boundp slotd 'setter)
6baf860c 386 (let ((writer (writer-function type))
387 (destroy (destroy-function type)))
388 (setf
64bce834 389 (slot-value slotd 'setter)
6baf860c 390 #'(lambda (value object)
7ce0497d 391 (let ((location (foreign-location object)))
6baf860c 392 (funcall destroy location offset) ; destroy old value
64bce834 393 (funcall writer value location offset))))))))
394
935a783c 395 (call-next-method))
396
7ce0497d 397 (defmethod compute-foreign-size ((class proxy-class))
398 nil)
935a783c 399
935a783c 400 ;; TODO: call some C code to detect this a compile time
401 (defconstant +struct-alignmen+ 4)
b44caf77 402
7ce0497d 403 (defun align-offset (size)
404 (if (zerop (mod size +struct-alignmen+))
405 size
406 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
407
b44caf77 408 (defmethod compute-slots ((class proxy-class))
7ce0497d 409 (let ((alien-slots
410 (remove-if-not
411 #'(lambda (slotd)
412 (eq (slot-definition-allocation slotd) :alien))
413 (class-direct-slots class))))
414 (when alien-slots
415 (loop
416 as offset = (align-offset (foreign-size
417 (most-specific-proxy-superclass class)))
418 then (align-offset
419 (+
420 (slot-definition-offset slotd)
421 (size-of (slot-definition-type slotd))))
422 for slotd in alien-slots
423 unless (slot-boundp slotd 'offset)
424 do (setf (slot-value slotd 'offset) offset))))
b44caf77 425 (call-next-method))
8ae7ddc2 426
7ce0497d 427 (defmethod compute-slots :after ((class proxy-class))
428 (when (and (class-finalized-p class) (not (slot-boundp class 'size)))
429 (let ((size (compute-foreign-size class)))
430 (when size
431 (setf (slot-value class 'size) size)))))
935a783c 432
433 (defmethod validate-superclass ((class proxy-class) (super standard-class))
434 (subtypep (class-name super) 'proxy))
435
7ce0497d 436 (defmethod foreign-size ((class-name symbol))
437 (foreign-size (find-class class-name))))
556b4a05 438
7ce0497d 439(defmethod foreign-size ((object proxy))
440 (foreign-size (class-of object)))
935a783c 441
7ce0497d 442
6baf860c 443(defmethod alien-type ((class proxy-class) &rest args)
444 (declare (ignore class args))
445 (alien-type 'pointer))
446
447(defmethod size-of ((class proxy-class) &rest args)
448 (declare (ignore class args))
449 (size-of 'pointer))
450
451(defmethod from-alien-form (location (class proxy-class) &rest args)
452 (declare (ignore args))
453 `(ensure-proxy-instance ',(class-name class) ,location))
454
455(defmethod from-alien-function ((class proxy-class) &rest args)
456 (declare (ignore args))
457 #'(lambda (location)
458 (ensure-proxy-instance class location)))
b44caf77 459
6baf860c 460(defmethod to-alien-form (instance (class proxy-class) &rest args)
461 (declare (ignore class args))
7ce0497d 462 `(foreign-location ,instance))
b44caf77 463
6baf860c 464(defmethod to-alien-function ((class proxy-class) &rest args)
465 (declare (ignore class args))
7ce0497d 466 #'foreign-location)
6baf860c 467
508d13a7 468(defmethod copy-from-alien-form (location (class proxy-class) &rest args)
469 (declare (ignore args))
470 (let ((class-name (class-name class)))
471 `(ensure-proxy-instance ',class-name
472 (reference-foreign ',class-name ,location))))
473
474(defmethod copy-from-alien-function ((class proxy-class) &rest args)
475 (declare (ignore args))
476 #'(lambda (location)
477 (ensure-proxy-instance class (reference-foreign class location))))
478
479(defmethod copy-to-alien-form (instance (class proxy-class) &rest args)
480 (declare (ignore args))
7ce0497d 481 `(reference-foreign ',(class-name class) (foreign-location ,instance)))
508d13a7 482
483(defmethod copy-to-alien-function ((class proxy-class) &rest args)
3d36c5d6 484 (declare (ignore args))
508d13a7 485 #'(lambda (instance)
7ce0497d 486 (reference-foreign class (foreign-location instance))))
508d13a7 487
6baf860c 488(defmethod writer-function ((class proxy-class) &rest args)
489 (declare (ignore args))
490 #'(lambda (instance location &optional (offset 0))
491 (assert (null-pointer-p (sap-ref-sap location offset)))
492 (setf
493 (sap-ref-sap location offset)
7ce0497d 494 (reference-foreign class (foreign-location instance)))))
b44caf77 495
6baf860c 496(defmethod reader-function ((class proxy-class) &rest args)
497 (declare (ignore args))
498 #'(lambda (location &optional (offset 0))
508d13a7 499 (let ((instance (sap-ref-sap location offset)))
500 (unless (null-pointer-p instance)
501 (ensure-proxy-instance class (reference-foreign class instance))))))
b44caf77 502
6baf860c 503(defmethod destroy-function ((class proxy-class) &rest args)
504 (declare (ignore args))
505 #'(lambda (location &optional (offset 0))
506 (unreference-foreign class (sap-ref-sap location offset))))
507
b6bf802c 508(defmethod unbound-value ((class proxy-class) &rest args)
556b4a05 509 (declare (ignore args))
b6bf802c 510 (values t nil))
6baf860c 511
1d06a422 512(defun ensure-proxy-instance (class location &rest initargs)
513 "Returns a proxy object representing the foreign object at the give
514location. If an existing object is not found in the cache
515MAKE-PROXY-INSTANCE is called to create one."
6baf860c 516 (unless (null-pointer-p location)
517 (or
253c1339 518 (let ((instance (find-cached-instance location)))
519 (when instance
520 (format t "Object found in cache: ~A~%" instance)
521 instance))
1d06a422 522 (let ((instance (apply #'make-proxy-instance class location initargs)))
523 (cache-instance instance)
524 instance))))
525
526(defgeneric make-proxy-instance (class location &key weak)
527 (:documentation "Creates a new proxy object representing the foreign
528object at the give location. If WEAK is non NIL the foreign memory
529will not be released when the proxy is garbage collected."))
530
253c1339 531(defmethod make-proxy-instance ((class symbol) location &rest initargs)
532 (apply #'make-proxy-instance (find-class class) location initargs))
1d06a422 533
534(defmethod make-proxy-instance ((class proxy-class) location &key weak)
1d06a422 535 (let ((instance (allocate-instance class)))
536 (setf (slot-value instance 'location) location)
537 (unless weak
538 (finalize instance (instance-finalizer instance)))
539 instance))
b44caf77 540
ba25fa44 541
542;;;; Superclasses for wrapping of C structures
b44caf77 543
6baf860c 544(defclass struct (proxy)
545 ()
7ce0497d 546 (:metaclass proxy-class)
547 (:size 0))
b44caf77 548
6baf860c 549(defmethod initialize-instance ((struct struct) &rest initargs)
b44caf77 550 (declare (ignore initargs))
9da5a342 551 (unless (slot-boundp struct 'location)
7ce0497d 552 (let ((size (foreign-size (class-of struct))))
9da5a342 553 (if (zerop size)
554 (error "~A has zero size" (class-of struct))
556b4a05 555 (setf (slot-value struct 'location) (allocate-memory size)))))
b44caf77 556 (call-next-method))
557
558
6baf860c 559;;;; Metaclasses used for subclasses of struct
560
561(defclass struct-class (proxy-class)
562 ())
b44caf77 563
82defe4d 564(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
565 (if (not (getf initargs :allocation))
566 (find-class 'direct-alien-slot-definition)
567 (call-next-method)))
568
6baf860c 569(defmethod reference-foreign ((class struct-class) location)
7ce0497d 570 (copy-memory location (foreign-size class)))
6baf860c 571
572(defmethod unreference-foreign ((class struct-class) location)
ba25fa44 573 (deallocate-memory location))
b44caf77 574
7ce0497d 575(defmethod compute-foreign-size ((class struct-class))
576 (let ((size (loop
577 for slotd in (class-slots class)
578 when (eq (slot-definition-allocation slotd) :alien)
579 maximize (+
580 (slot-definition-offset slotd)
581 (size-of (slot-definition-type slotd))))))
582 (+ size (mod size +struct-alignmen+))))
583
253c1339 584(defmethod weak-reader-function ((class struct-class) &rest args)
585 (declare (ignore args))
586 #'(lambda (location &optional (offset 0))
587 (let ((instance (sap-ref-sap location offset)))
588 (unless (null-pointer-p instance)
589 (ensure-proxy-instance class instance :weak t)))))
590
b44caf77 591
6baf860c 592(defclass static-struct-class (struct-class)
593 ())
b44caf77 594
6baf860c 595(defmethod reference-foreign ((class static-struct-class) location)
596 (declare (ignore class))
ba25fa44 597 location)
b44caf77 598
6baf860c 599(defmethod unreference-foreign ((class static-struct-class) location)
600 (declare (ignore class location))
ba25fa44 601 nil)
b4edcbf0 602
603
604;;; Pseudo type for structs which are inlined in other objects
605
606(defmethod size-of ((type (eql 'inlined)) &rest args)
607 (declare (ignore type))
7ce0497d 608 (foreign-size (first args)))
b4edcbf0 609
610(defmethod reader-function ((type (eql 'inlined)) &rest args)
611 (declare (ignore type))
612 (destructuring-bind (class) args
613 #'(lambda (location &optional (offset 0))
614 (ensure-proxy-instance class
615 (reference-foreign class (sap+ location offset))))))
616
253c1339 617(defmethod writer-function ((type (eql 'inlined)) &rest args)
618 (declare (ignore type))
619 (destructuring-bind (class) args
620 #'(lambda (instance location &optional (offset 0))
621 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
622
b4edcbf0 623(defmethod destroy-function ((type (eql 'inlined)) &rest args)
624 (declare (ignore args))
625 #'(lambda (location &optional (offset 0))
626 (declare (ignore location offset))))
627
628(export 'inlined)