chiark / gitweb /
Referencing gobject classes properly
[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
3005806e 23;; $Id: proxy.lisp,v 1.28 2006-02-06 18:12:19 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)
46 ())
94f15c3c 47
e2ebafb1 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
94f15c3c 67
9adccb27 68(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
e2ebafb1 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))))
94f15c3c 73
9adccb27 74(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
e2ebafb1 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))))
94f15c3c 79
4d83a8a6 80
81(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
eeda1c2d 82 (if (not (slot-boundp slotd 'getter))
83 (setf
4d83a8a6 84 (slot-value slotd 'reader-function)
eeda1c2d 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
12b7df04 103 (setq reader
104 (mkbinding getter
105 (slot-definition-type slotd) 'pointer)))
09f6e237 106 (funcall reader (foreign-location object))))))))))
eeda1c2d 107
4d83a8a6 108 (setf
eeda1c2d 109 (slot-value slotd 'boundp-function)
110 (cond
eeda1c2d 111 ((slot-boundp slotd 'unbound)
112 (let ((unbound-value (slot-value slotd 'unbound)))
12b7df04 113 #'(lambda (object)
114 (not (eq (funcall getter-function object) unbound-value)))))
115 ((slot-boundp slotd 'boundp)
116 (let ((boundp (slot-value slotd 'boundp)))
eeda1c2d 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)))
09f6e237 127 (funcall reader (foreign-location object))))))))
12b7df04 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))))
eeda1c2d 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)))
12b7df04 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)))))
eeda1c2d 146 ((slot-boundp slotd 'boundp)
147 (let ((boundp-function (slot-value slotd 'boundp-function)))
12b7df04 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)))))))
eeda1c2d 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
4d83a8a6 170 (etypecase setter
171 (function setter)
eeda1c2d 172 ((or symbol cons)
173 #'(lambda (value object)
174 (funcall (fdefinition setter) value object)))
7d1ddc9e 175 (string
eeda1c2d 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))))
09f6e237 184 (funcall writer (foreign-location object) value)))))))))
eeda1c2d 185
4d83a8a6 186 (initialize-internal-slot-gfs (slot-definition-name slotd)))
187
188
189
eeda1c2d 190(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
4d83a8a6 191 nil)
192
9adccb27 193(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
eeda1c2d 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)))
4d83a8a6 209 (call-next-method)))
210
94f15c3c 211
94f15c3c 212(defmethod slot-value-using-class
9adccb27 213 ((class virtual-slots-class) (object standard-object)
94f15c3c 214 (slotd effective-virtual-slot-definition))
4d83a8a6 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))))
94f15c3c 218
94f15c3c 219(defmethod slot-boundp-using-class
9adccb27 220 ((class virtual-slots-class) (object standard-object)
94f15c3c 221 (slotd effective-virtual-slot-definition))
4d83a8a6 222 (funcall (slot-value slotd 'boundp-function) object))
223
224(defmethod (setf slot-value-using-class)
9adccb27 225 (value (class virtual-slots-class) (object standard-object)
94f15c3c 226 (slotd effective-virtual-slot-definition))
4d83a8a6 227 (funcall (slot-value slotd 'writer-function) value object))
228
229
94f15c3c 230(defmethod validate-superclass
9adccb27 231 ((class virtual-slots-class) (super standard-class))
94f15c3c 232 t)
233
234
235;;;; Proxy cache
236
237(internal *instance-cache*)
238(defvar *instance-cache* (make-hash-table :test #'eql))
239
982a215a 240(defun cache-instance (instance &optional (weak-ref t))
94f15c3c 241 (setf
09f6e237 242 (gethash (sap-int (foreign-location instance)) *instance-cache*)
982a215a 243 (if weak-ref
244 (make-weak-pointer instance)
245 instance)))
94f15c3c 246
247(defun find-cached-instance (location)
73572c12 248 (let ((ref (gethash (sap-int location) *instance-cache*)))
94f15c3c 249 (when ref
982a215a 250 (if (weak-pointer-p ref)
251 (weak-pointer-value ref)
252 ref))))
94f15c3c 253
0f134a29 254(defun instance-cached-p (location)
73572c12 255 (gethash (sap-int location) *instance-cache*))
0f134a29 256
94f15c3c 257(defun remove-cached-instance (location)
73572c12 258 (remhash (sap-int location) *instance-cache*))
94f15c3c 259
9adccb27 260;; For debuging
982a215a 261(defun list-cached-instances ()
9adccb27 262 (let ((instances ()))
263 (maphash #'(lambda (location ref)
264 (declare (ignore location))
982a215a 265 (push ref instances))
9adccb27 266 *instance-cache*)
267 instances))
268
94f15c3c 269
270
271;;;; Proxy for alien instances
272
4a64c16d 273;; TODO: add a ref-counted-proxy subclass
9adccb27 274(defclass proxy ()
09f6e237 275 ((location :allocation :special :reader foreign-location :type pointer))
e2ebafb1 276 (:metaclass virtual-slots-class))
94f15c3c 277
9adccb27 278(defgeneric instance-finalizer (object))
279(defgeneric reference-foreign (class location))
280(defgeneric unreference-foreign (class location))
4a64c16d 281(defgeneric invalidate-instance (object))
9adccb27 282
3b167652 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
9adccb27 289(defmethod unreference-foreign :around ((class class) location)
290 (unless (null-pointer-p location)
09f6e237 291 (call-next-method)))
94f15c3c 292
0f134a29 293(defmethod print-object ((instance proxy) stream)
294 (print-unreadable-object (instance stream :type t :identity nil)
09f6e237 295 (if (slot-boundp instance 'location)
296 (format stream "at 0x~X" (sap-int (foreign-location instance)))
297 (write-string "at \"unbound\"" stream))))
94f15c3c 298
8958fa4a 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))))
94f15c3c 305
306(defmethod instance-finalizer ((instance proxy))
09f6e237 307 (let ((location (foreign-location instance))
9adccb27 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 ()
1dbf4216 312 (remove-cached-instance location)
9adccb27 313 (unreference-foreign class location))))
12d0437e 314
4a64c16d 315(defmethod invalidate-instance ((instance proxy))
316 (remove-cached-instance (foreign-location instance))
317 (slot-makunbound instance 'location))
318
94f15c3c 319
320;;;; Metaclass used for subclasses of proxy
321
73572c12 322(defgeneric most-specific-proxy-superclass (class))
323(defgeneric direct-proxy-superclass (class))
09f6e237 324(defgeneric compute-foreign-size (class))
73572c12 325
326
94f15c3c 327(eval-when (:compile-toplevel :load-toplevel :execute)
9adccb27 328 (defclass proxy-class (virtual-slots-class)
09f6e237 329 ((size :reader foreign-size)))
94f15c3c 330
331 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
12d0437e 332 ((allocation :initform :alien)
333 (offset :reader slot-definition-offset :initarg :offset)))
94f15c3c 334
335 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
4d83a8a6 336 ((offset :reader slot-definition-offset :initarg :offset)))
12d0437e 337
94f15c3c 338 (defmethod most-specific-proxy-superclass ((class proxy-class))
339 (find-if
340 #'(lambda (class)
341 (subtypep (class-name class) 'proxy))
4d83a8a6 342 (cdr (compute-class-precedence-list class))))
73572c12 343
12d0437e 344 (defmethod direct-proxy-superclass ((class proxy-class))
345 (find-if
346 #'(lambda (class)
347 (subtypep (class-name class) 'proxy))
4d83a8a6 348 (class-direct-superclasses class)))
349
eeda1c2d 350 (defmethod shared-initialize ((class proxy-class) names &key size)
94f15c3c 351 (call-next-method)
12d0437e 352 (cond
4d83a8a6 353 (size (setf (slot-value class 'size) (first size)))
9adccb27 354 ((slot-boundp class 'size) (slot-makunbound class 'size))))
09f6e237 355
4d83a8a6 356 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 357 (case (getf initargs :allocation)
e2ebafb1 358 (:alien (find-class 'direct-alien-slot-definition))
94f15c3c 359 (t (call-next-method))))
4d83a8a6 360
361 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 362 (case (getf initargs :allocation)
363 (:alien (find-class 'effective-alien-slot-definition))
94f15c3c 364 (t (call-next-method))))
365
4d83a8a6 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
9adccb27 377 (let ((type (slot-definition-type slotd)))
eeda1c2d 378 (unless (slot-boundp slotd 'getter)
9adccb27 379 (let ((reader (reader-function type)))
380 (setf
eeda1c2d 381 (slot-value slotd 'getter)
9adccb27 382 #'(lambda (object)
09f6e237 383 (funcall reader (foreign-location object) offset)))))
4d83a8a6 384
eeda1c2d 385 (unless (slot-boundp slotd 'setter)
9adccb27 386 (let ((writer (writer-function type))
387 (destroy (destroy-function type)))
388 (setf
eeda1c2d 389 (slot-value slotd 'setter)
9adccb27 390 #'(lambda (value object)
09f6e237 391 (let ((location (foreign-location object)))
9adccb27 392 (funcall destroy location offset) ; destroy old value
eeda1c2d 393 (funcall writer value location offset))))))))
394
4d83a8a6 395 (call-next-method))
396
09f6e237 397 (defmethod compute-foreign-size ((class proxy-class))
398 nil)
4d83a8a6 399
4d83a8a6 400 ;; TODO: call some C code to detect this a compile time
401 (defconstant +struct-alignmen+ 4)
94f15c3c 402
09f6e237 403 (defun align-offset (size)
404 (if (zerop (mod size +struct-alignmen+))
405 size
406 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
407
94f15c3c 408 (defmethod compute-slots ((class proxy-class))
09f6e237 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))))
94f15c3c 425 (call-next-method))
3e15002d 426
09f6e237 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)))))
4d83a8a6 432
433 (defmethod validate-superclass ((class proxy-class) (super standard-class))
434 (subtypep (class-name super) 'proxy))
435
09f6e237 436 (defmethod foreign-size ((class-name symbol))
437 (foreign-size (find-class class-name))))
47a11c16 438
09f6e237 439(defmethod foreign-size ((object proxy))
440 (foreign-size (class-of object)))
4d83a8a6 441
09f6e237 442
9adccb27 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)))
94f15c3c 459
9adccb27 460(defmethod to-alien-form (instance (class proxy-class) &rest args)
461 (declare (ignore class args))
09f6e237 462 `(foreign-location ,instance))
94f15c3c 463
9adccb27 464(defmethod to-alien-function ((class proxy-class) &rest args)
465 (declare (ignore class args))
09f6e237 466 #'foreign-location)
9adccb27 467
9ca5565a 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))
09f6e237 481 `(reference-foreign ',(class-name class) (foreign-location ,instance)))
9ca5565a 482
483(defmethod copy-to-alien-function ((class proxy-class) &rest args)
73572c12 484 (declare (ignore args))
9ca5565a 485 #'(lambda (instance)
09f6e237 486 (reference-foreign class (foreign-location instance))))
9ca5565a 487
9adccb27 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)
09f6e237 494 (reference-foreign class (foreign-location instance)))))
94f15c3c 495
9adccb27 496(defmethod reader-function ((class proxy-class) &rest args)
497 (declare (ignore args))
3005806e 498 #'(lambda (location &optional (offset 0) weak-p)
499 (declare (ignore weak-p))
9ca5565a 500 (let ((instance (sap-ref-sap location offset)))
501 (unless (null-pointer-p instance)
502 (ensure-proxy-instance class (reference-foreign class instance))))))
94f15c3c 503
9adccb27 504(defmethod destroy-function ((class proxy-class) &rest args)
505 (declare (ignore args))
506 #'(lambda (location &optional (offset 0))
507 (unreference-foreign class (sap-ref-sap location offset))))
508
12b7df04 509(defmethod unbound-value ((class proxy-class) &rest args)
47a11c16 510 (declare (ignore args))
12b7df04 511 (values t nil))
9adccb27 512
8958fa4a 513(defun ensure-proxy-instance (class location &rest initargs)
514 "Returns a proxy object representing the foreign object at the give
515location. If an existing object is not found in the cache
516MAKE-PROXY-INSTANCE is called to create one."
9adccb27 517 (unless (null-pointer-p location)
518 (or
aaced14e 519 #-debug-ref-counting(find-cached-instance location)
520 #+debug-ref-counting
4a64c16d 521 (let ((instance (find-cached-instance location)))
522 (when instance
523 (format t "Object found in cache: ~A~%" instance)
524 instance))
8958fa4a 525 (let ((instance (apply #'make-proxy-instance class location initargs)))
526 (cache-instance instance)
527 instance))))
528
529(defgeneric make-proxy-instance (class location &key weak)
530 (:documentation "Creates a new proxy object representing the foreign
531object at the give location. If WEAK is non NIL the foreign memory
532will not be released when the proxy is garbage collected."))
533
4a64c16d 534(defmethod make-proxy-instance ((class symbol) location &rest initargs)
535 (apply #'make-proxy-instance (find-class class) location initargs))
8958fa4a 536
537(defmethod make-proxy-instance ((class proxy-class) location &key weak)
8958fa4a 538 (let ((instance (allocate-instance class)))
539 (setf (slot-value instance 'location) location)
540 (unless weak
541 (finalize instance (instance-finalizer instance)))
542 instance))
94f15c3c 543
12d0437e 544
545;;;; Superclasses for wrapping of C structures
94f15c3c 546
9adccb27 547(defclass struct (proxy)
548 ()
09f6e237 549 (:metaclass proxy-class)
550 (:size 0))
94f15c3c 551
9adccb27 552(defmethod initialize-instance ((struct struct) &rest initargs)
94f15c3c 553 (declare (ignore initargs))
ec1a4146 554 (unless (slot-boundp struct 'location)
09f6e237 555 (let ((size (foreign-size (class-of struct))))
ec1a4146 556 (if (zerop size)
557 (error "~A has zero size" (class-of struct))
47a11c16 558 (setf (slot-value struct 'location) (allocate-memory size)))))
94f15c3c 559 (call-next-method))
560
561
9adccb27 562;;;; Metaclasses used for subclasses of struct
563
564(defclass struct-class (proxy-class)
565 ())
94f15c3c 566
e2ebafb1 567(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
568 (if (not (getf initargs :allocation))
569 (find-class 'direct-alien-slot-definition)
570 (call-next-method)))
571
9adccb27 572(defmethod reference-foreign ((class struct-class) location)
09f6e237 573 (copy-memory location (foreign-size class)))
9adccb27 574
575(defmethod unreference-foreign ((class struct-class) location)
12d0437e 576 (deallocate-memory location))
94f15c3c 577
09f6e237 578(defmethod compute-foreign-size ((class struct-class))
579 (let ((size (loop
580 for slotd in (class-slots class)
581 when (eq (slot-definition-allocation slotd) :alien)
582 maximize (+
583 (slot-definition-offset slotd)
584 (size-of (slot-definition-type slotd))))))
585 (+ size (mod size +struct-alignmen+))))
586
3005806e 587(defmethod reader-function ((class struct-class) &rest args)
4a64c16d 588 (declare (ignore args))
3005806e 589 #'(lambda (location &optional (offset 0) weak-p)
4a64c16d 590 (let ((instance (sap-ref-sap location offset)))
591 (unless (null-pointer-p instance)
3005806e 592 (if weak-p
593 (ensure-proxy-instance class instance :weak t)
594 (ensure-proxy-instance class (reference-foreign class instance)))))))
4a64c16d 595
94f15c3c 596
9adccb27 597(defclass static-struct-class (struct-class)
598 ())
94f15c3c 599
9adccb27 600(defmethod reference-foreign ((class static-struct-class) location)
601 (declare (ignore class))
12d0437e 602 location)
94f15c3c 603
9adccb27 604(defmethod unreference-foreign ((class static-struct-class) location)
605 (declare (ignore class location))
12d0437e 606 nil)
bde0b906 607
3005806e 608(defmethod reader-function ((class struct-class) &rest args)
609 (declare (ignore args))
610 #'(lambda (location &optional (offset 0) weak-p)
611 (declare (ignore weak-p))
612 (let ((instance (sap-ref-sap location offset)))
613 (unless (null-pointer-p instance)
614 (ensure-proxy-instance class instance :weak t)))))
615
bde0b906 616
617;;; Pseudo type for structs which are inlined in other objects
618
619(defmethod size-of ((type (eql 'inlined)) &rest args)
620 (declare (ignore type))
09f6e237 621 (foreign-size (first args)))
bde0b906 622
623(defmethod reader-function ((type (eql 'inlined)) &rest args)
624 (declare (ignore type))
625 (destructuring-bind (class) args
3005806e 626 #'(lambda (location &optional (offset 0) weak-p)
627 (declare (ignore weak-p))
bde0b906 628 (ensure-proxy-instance class
629 (reference-foreign class (sap+ location offset))))))
630
4a64c16d 631(defmethod writer-function ((type (eql 'inlined)) &rest args)
632 (declare (ignore type))
633 (destructuring-bind (class) args
634 #'(lambda (instance location &optional (offset 0))
635 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
636
bde0b906 637(defmethod destroy-function ((type (eql 'inlined)) &rest args)
638 (declare (ignore args))
639 #'(lambda (location &optional (offset 0))
640 (declare (ignore location offset))))
641
642(export 'inlined)