chiark / gitweb /
Added platform more independent memory access functions
[clg] / gffi / proxy.lisp
CommitLineData
4e968638 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 2000-2006 Espen S. Johnsen <espen@users.sf.net>
3;;
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:
11;;
12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
14;;
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.
22
8741fc3a 23;; $Id: proxy.lisp,v 1.8 2007-05-10 20:23:28 espen Exp $
4e968638 24
25(in-package "GFFI")
26
27
28;;;; Proxy cache
29
30(defvar *instance-cache* (make-hash-table :test #'eql))
31
32(defun cache-instance (instance &optional (weak-ref t))
33 (setf
34 (gethash (pointer-address (foreign-location instance)) *instance-cache*)
35 (if weak-ref
36 (make-weak-pointer instance)
37 instance)))
38
39(defun find-cached-instance (location)
40 (let ((ref (gethash (pointer-address location) *instance-cache*)))
41 (when ref
42 (if (weak-pointer-p ref)
43 (weak-pointer-value ref)
44 ref))))
45
46(defun instance-cached-p (location)
47 (gethash (pointer-address location) *instance-cache*))
48
49(defun remove-cached-instance (location)
50 (remhash (pointer-address location) *instance-cache*))
51
52;; For debuging
53(defun list-cached-instances ()
54 (let ((instances ()))
55 (maphash #'(lambda (location ref)
56 (declare (ignore location))
57 (push ref instances))
58 *instance-cache*)
59 instances))
60
61;; Instances that gets invalidated tend to be short lived, but created
62;; in large numbers. So we're keeping them in a hash table to be able
63;; to reuse them (and thus reduce consing)
64(defvar *invalidated-instance-cache* (make-hash-table :test #'eql))
65
66(defun cache-invalidated-instance (instance)
67 (push instance
68 (gethash (class-of instance) *invalidated-instance-cache*)))
69
70(defun find-invalidated-instance (class)
71 (when (gethash class *invalidated-instance-cache*)
72 (pop (gethash class *invalidated-instance-cache*))))
73
74(defun list-invalidated-instances ()
75 (let ((instances ()))
76 (maphash #'(lambda (location ref)
77 (declare (ignore location))
78 (push ref instances))
79 *invalidated-instance-cache*)
80 instances))
81
82
83
84;;;; Proxy for alien instances
85
61b2bec6 86#?(or (sbcl>= 0 9 17) (featurep :clisp))
87(defvar *foreign-instance-locations*
88 (make-hash-table #+clisp :weak #+sbcl :weakness :key))
4e968638 89
61308fc4 90
4e968638 91(eval-when (:compile-toplevel :load-toplevel :execute)
92 (defclass proxy (virtual-slots-object)
61b2bec6 93 (#?-(or (sbcl>= 0 9 17) (featurep :clisp))(%location :special t :type pointer))
4e968638 94 (:metaclass virtual-slots-class)))
95
96(defgeneric instance-finalizer (instance))
97(defgeneric reference-function (class))
98(defgeneric unreference-function (class))
99(defgeneric invalidate-instance (instance &optional finalize-p))
100(defgeneric allocate-foreign (object &key &allow-other-keys))
101
61b2bec6 102#?-(or (sbcl>= 0 9 17) (featurep :clisp))
103(progn
104 (defun foreign-location (instance)
105 (slot-value instance '%location))
4e968638 106
61b2bec6 107 (defun (setf foreign-location) (location instance)
108 (setf (slot-value instance '%location) location))
109
110 (defun proxy-valid-p (instance)
111 (slot-boundp instance '%location)))
112
113#?(or (sbcl>= 0 9 17) (featurep :clisp))
114(progn
115 (defun foreign-location (instance)
116 (gethash instance *foreign-instance-locations*))
117
118 (defun (setf foreign-location) (location instance)
119 (setf (gethash instance *foreign-instance-locations*) location))
120
121 (defun proxy-valid-p (instance)
122 (and (gethash instance *foreign-instance-locations*) t)))
4e968638 123
4e968638 124
125(defmethod reference-function ((name symbol))
126 (reference-function (find-class name)))
127
128(defmethod unreference-function ((name symbol))
129 (unreference-function (find-class name)))
130
131(defmethod print-object ((instance proxy) stream)
132 (print-unreadable-object (instance stream :type t :identity nil)
133 (if (proxy-valid-p instance)
134 (format stream "at 0x~X" (pointer-address (foreign-location instance)))
135 (write-string "at \"unbound\"" stream))))
136
137
138(defmethod initialize-instance :around ((instance proxy) &rest initargs &key &allow-other-keys)
139 (setf
140 (foreign-location instance)
141 (apply #'allocate-foreign instance initargs))
142 (prog1
143 (call-next-method)
144 (cache-instance instance)
145 (finalize instance (instance-finalizer instance))))
146
147(defmethod instance-finalizer :around ((instance proxy))
148 (let ((finalizer (call-next-method)))
149 (let ((location (foreign-location instance)))
150 #+(or cmu sbcl)
151 #'(lambda ()
152 (remove-cached-instance location)
153 (funcall finalizer))
154 #+clisp
155 #'(lambda (instance)
156 (declare (ignore instance))
157 (remove-cached-instance location)
158 (funcall finalizer)))))
159
160(defmethod instance-finalizer ((instance proxy))
161 (let ((location (foreign-location instance))
162 (unref (unreference-function (class-of instance))))
163 #'(lambda ()
164 (funcall unref location))))
165
61b2bec6 166;; FINALIZE-P should always be the same as the keyword argument
167;; :FINALZIE given to MAKE-PROXY-INSTANCE or non NIL if the proxy was
168;; created with MAKE-INSTANCE
4e968638 169(defmethod invalidate-instance ((instance proxy) &optional finalize-p)
8741fc3a 170 #+clisp(declare (ignore finalize-p))
4e968638 171 (remove-cached-instance (foreign-location instance))
172 #+(or sbcl cmu)
173 (progn
174 (when finalize-p
175 (funcall (instance-finalizer instance)))
61b2bec6 176 #?-(sbcl>= 0 9 17)(slot-makunbound instance '%location)
177 #?(sbcl>= 0 9 17)(remhash instance *foreign-instance-locations*)
4e968638 178 (cancel-finalization instance))
584285fb 179 ;; We can't cache invalidated instances in CLISP beacuse it is
4e968638 180 ;; not possible to cancel finalization
181 #-clisp(cache-invalidated-instance instance))
182
183
184;;;; Metaclass used for subclasses of proxy
185
186(eval-when (:compile-toplevel :load-toplevel :execute)
187 (defclass proxy-class (virtual-slots-class)
188 ((size :accessor foreign-size)
189 (packed :reader foreign-slots-packed-p)
190 (ref :reader reference-function)
191 (unref :reader unreference-function)))
192
193 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
194 ((offset :reader slot-definition-offset :initarg :offset))
195 (:default-initargs :allocation :alien))
196
197 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
198 ((offset :reader slot-definition-offset :initarg :offset)))
199
200 (defclass direct-virtual-alien-slot-definition (direct-virtual-slot-definition)
201 ())
202
203 (defclass effective-virtual-alien-slot-definition (effective-virtual-slot-definition)
204 ())
205
206 (defgeneric foreign-size-p (class))
207 (defgeneric most-specific-proxy-superclass (class))
208 (defgeneric direct-proxy-superclass (class))
209
210 (defmethod foreign-size-p ((class proxy-class))
211 (slot-boundp class 'size))
212
213 (defmethod most-specific-proxy-superclass ((class proxy-class))
214 (find-if
215 #'(lambda (class)
216 (subtypep (class-name class) 'proxy))
217 (cdr (compute-class-precedence-list class))))
218
219 (defmethod direct-proxy-superclass ((class proxy-class))
220 (find-if
221 #'(lambda (class)
222 (subtypep (class-name class) 'proxy))
223 (class-direct-superclasses class)))
224
225 (defmethod shared-initialize ((class proxy-class) names
226 &key size packed ref unref)
227 (declare (ignore names))
228 (cond
229 (size (setf (slot-value class 'size) (first size)))
230 ((slot-boundp class 'size) (slot-makunbound class 'size)))
231 (setf (slot-value class 'packed) (first packed))
232 (when ref
233 (setf (slot-value class 'ref) (first ref)))
234 (when unref
235 (setf (slot-value class 'unref) (first unref)))
236 (call-next-method))
237
238 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
239 (case (getf initargs :allocation)
240 (:alien (find-class 'direct-alien-slot-definition))
241 (:virtual (find-class 'direct-virtual-alien-slot-definition))
242 (t (call-next-method))))
243
244 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
245 (case (getf initargs :allocation)
246 (:alien (find-class 'effective-alien-slot-definition))
247 (:virtual (find-class 'effective-virtual-alien-slot-definition))
248 (t (call-next-method))))
249
250
251 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
252 (if (eq (slot-definition-allocation (first direct-slotds)) :alien)
253 (nconc
254 (list :offset (most-specific-slot-value direct-slotds 'offset))
255 (call-next-method))
256 (call-next-method)))
257
2bd78f93 258 (defmethod slot-readable-p ((slotd effective-alien-slot-definition))
259 (declare (ignore slotd))
260 t)
4e968638 261
584285fb 262 (defmethod compute-slot-reader-function ((slotd effective-alien-slot-definition) &optional signal-unbound-p)
263 (declare (ignore signal-unbound-p))
4e968638 264 (let* ((type (slot-definition-type slotd))
265 (offset (slot-definition-offset slotd))
266 (reader (reader-function type)))
267 #'(lambda (object)
268 (funcall reader (foreign-location object) offset))))
269
2bd78f93 270 (defmethod slot-writable-p ((slotd effective-alien-slot-definition))
271 (declare (ignore slotd))
272 t)
273
4e968638 274 (defmethod compute-slot-writer-function ((slotd effective-alien-slot-definition))
275 (let* ((type (slot-definition-type slotd))
276 (offset (slot-definition-offset slotd))
277 (writer (writer-function type))
278 (destroy (destroy-function type)))
279 #'(lambda (value object)
280 (let ((location (foreign-location object)))
281 (funcall destroy location offset) ; destroy old value
282 (funcall writer value location offset))
283 value)))
284
584285fb 285 (defmethod compute-slot-reader-function ((slotd effective-virtual-alien-slot-definition) &optional signal-unbound-p)
286 (declare (ignore signal-unbound-p))
4e968638 287 (if (and (slot-boundp slotd 'getter) (stringp (slot-definition-getter slotd)))
288 (let ((getter (slot-definition-getter slotd))
289 (type (slot-definition-type slotd))
290 (reader nil))
291 #'(lambda (object)
292 (unless reader
293 (setq reader (mkbinding getter type 'pointer)))
294 (funcall reader (foreign-location object))))
295 (call-next-method)))
296
297 (defmethod compute-slot-writer-function ((slotd effective-virtual-alien-slot-definition))
298 (if (and (slot-boundp slotd 'setter) (stringp (slot-definition-setter slotd)))
299 (let ((setter (slot-definition-setter slotd))
300 (type (slot-definition-type slotd))
301 (writer nil))
302 #'(lambda (value object)
303 (unless writer
304 (setq writer (mkbinding setter nil 'pointer type)))
305 (funcall writer (foreign-location object) value)))
306 (call-next-method)))
307
90e8bbf6 308 (defun adjust-offset (offset type &optional packed-p)
309 (let ((alignment (type-alignment type)))
310 (if (or packed-p (zerop (mod offset alignment)))
311 offset
312 (+ offset (- alignment (mod offset alignment))))))
4e968638 313
314 (defmethod compute-slots ((class proxy-class))
315 (let ((alien-slots (remove-if-not
316 #'(lambda (allocation) (eq allocation :alien))
317 (class-direct-slots class)
318 :key #'slot-definition-allocation)))
319 (when alien-slots
320 (loop
321 with packed-p = (foreign-slots-packed-p class)
90e8bbf6 322 for slotd in alien-slots
323 as offset = (adjust-offset
4e968638 324 (foreign-size (most-specific-proxy-superclass class))
90e8bbf6 325 (slot-definition-type slotd)
4e968638 326 packed-p)
90e8bbf6 327 then (adjust-offset offset (slot-definition-type slotd) packed-p)
328 do (if (slot-boundp slotd 'offset)
329 (setf offset (slot-value slotd 'offset))
330 (setf (slot-value slotd 'offset) offset))
331 (incf offset (size-of (slot-definition-type slotd))))))
4e968638 332 (call-next-method))
333
334 (defmethod validate-superclass ((class proxy-class) (super standard-class))
335 (subtypep (class-name super) 'proxy))
336
337 (defmethod foreign-size ((class-name symbol))
338 (foreign-size (find-class class-name))))
339
340(defmethod foreign-size ((object proxy))
341 (foreign-size (class-of object)))
342
343(define-type-method alien-type ((type proxy))
344 (declare (ignore type))
345 (alien-type 'pointer))
346
347(define-type-method size-of ((type proxy) &key inlined)
348 (assert-not-inlined type inlined)
349 (size-of 'pointer))
350
90e8bbf6 351(define-type-method type-alignment ((type proxy) &key inlined)
352 (assert-not-inlined type inlined)
353 (type-alignment 'pointer))
354
4e968638 355(define-type-method from-alien-form ((type proxy) form &key (ref :free))
356 (let ((class (type-expand type)))
357 (ecase ref
358 (:free `(ensure-proxy-instance ',class ,form :reference nil))
359 (:copy `(ensure-proxy-instance ',class ,form))
360 ((:static :temp) `(ensure-proxy-instance ',class ,form
361 :reference nil :finalize nil)))))
362
363(define-type-method from-alien-function ((type proxy) &key (ref :free))
364 (let ((class (type-expand type)))
365 (ecase ref
366 (:free
367 #'(lambda (location)
368 (ensure-proxy-instance class location :reference nil)))
369 (:copy
370 #'(lambda (location)
371 (ensure-proxy-instance class location)))
372 ((:static :temp)
373 #'(lambda (location)
374 (ensure-proxy-instance class location :reference nil :finalize nil))))))
375
376(define-type-method to-alien-form ((type proxy) instance &optional copy-p)
377 (if copy-p
378 (let* ((class (type-expand type))
379 (ref (reference-function class)))
380 (if (symbolp ref)
381 `(,ref (foreign-location ,instance))
382 `(funcall (reference-function ',class)
383 (foreign-location ,instance))))
384 `(foreign-location ,instance)))
385
386(define-type-method to-alien-function ((type proxy) &optional copy-p)
387 (if copy-p
388 (let ((ref (reference-function (type-expand type))))
389 #'(lambda (instance)
390 (funcall ref (foreign-location instance))))
391 #'foreign-location))
392
4e968638 393(define-type-method writer-function ((type proxy) &key temp inlined)
394 (assert-not-inlined type inlined)
395 (if temp
396 #'(lambda (instance location &optional (offset 0))
397 (assert (null-pointer-p (ref-pointer location offset)))
398 (setf (ref-pointer location offset) (foreign-location instance)))
399 (let ((ref (reference-function (type-expand type))))
400 #'(lambda (instance location &optional (offset 0))
401 (assert (null-pointer-p (ref-pointer location offset)))
402 (setf
403 (ref-pointer location offset)
404 (funcall ref (foreign-location instance)))))))
405
406(define-type-method reader-function ((type proxy) &key (ref :read) inlined)
407 (assert-not-inlined type inlined)
408 (let ((class (type-expand type)))
409 (ecase ref
410 (:read
411 #'(lambda (location &optional (offset 0))
412 (let ((instance (ref-pointer location offset)))
413 (unless (null-pointer-p instance)
414 (ensure-proxy-instance class instance)))))
415 (:peek
416 #'(lambda (location &optional (offset 0))
417 (let ((instance (ref-pointer location offset)))
418 (unless (null-pointer-p instance)
419 (ensure-proxy-instance class instance
420 :reference nil :finalize nil)))))
421 (:get
422 #'(lambda (location &optional (offset 0))
423 (let ((instance (ref-pointer location offset)))
424 (unless (null-pointer-p instance)
425 (prog1
426 (ensure-proxy-instance class instance :reference nil)
427 (setf (ref-pointer location offset) (make-pointer 0))))))))))
428
429(define-type-method destroy-function ((type proxy) &key temp inlined)
430 (assert-not-inlined type inlined)
431 (if temp
432 #'(lambda (location &optional (offset 0))
433 (setf (ref-pointer location offset) (make-pointer 0)))
434 (let ((unref (unreference-function (type-expand type))))
435 #'(lambda (location &optional (offset 0))
436 (unless (null-pointer-p (ref-pointer location offset))
437 (funcall unref (ref-pointer location offset))
438 (setf (ref-pointer location offset) (make-pointer 0)))))))
439
440(define-type-method copy-function ((type proxy) &key inlined)
441 (assert-not-inlined type inlined)
442 (let ((ref (reference-function (type-expand type))))
443 #'(lambda (from to &optional (offset 0))
444 (let ((instance (ref-pointer from offset)))
445 (unless (null-pointer-p instance)
446 (funcall ref instance))
447 (setf (ref-pointer to offset) instance)))))
448
449(define-type-method unbound-value ((type proxy))
450 (declare (ignore type))
451 nil)
452
453(defun ensure-proxy-instance (class location &rest initargs)
454 "Returns a proxy object representing the foreign object at the give
455location. If an existing proxy object is not found,
456MAKE-PROXY-INSTANCE is called to create a new one. A second return
457value indicates whether a new proxy was created or not."
458 (unless (null-pointer-p location)
459 (or
460 #-debug-ref-counting(find-cached-instance location)
461 #+debug-ref-counting
462 (let ((instance (find-cached-instance location)))
463 (when instance
464 (format t "Object found in cache: ~A~%" instance)
465 instance))
466 (values
467 (apply #'make-proxy-instance class location initargs)
468 t))))
469
470(defgeneric make-proxy-instance (class location &key reference finalize)
471 (:documentation "Creates a new proxy object representing the foreign
472object at the give location."))
473
474(defmethod make-proxy-instance ((class symbol) location &rest initargs)
475 (apply #'make-proxy-instance (find-class class) location initargs))
476
477(defmethod make-proxy-instance ((class proxy-class) location
478 &key (reference t) (finalize t))
479 (let ((instance
480 (or
481 (find-invalidated-instance class)
482 (allocate-instance class))))
483 (setf (foreign-location instance)
484 (if reference
485 (funcall (reference-function class) location)
486 location))
487 (finalize instance
488 (if finalize
489 (instance-finalizer instance)
490 ;; We still need to remove the instance from the cache even if we
491 ;; don't do normal finalization
492 (let ((location (foreign-location instance)))
493 #+(or cmu sbcl)
494 #'(lambda ()
495 (remove-cached-instance location))
496 #+clisp
497 #'(lambda (instance)
498 (declare (ignore instance))
499 (remove-cached-instance location)))))
500 (cache-instance instance)
501 instance))
502
65a7f9a0 503;;;; Superclass for ref-counted objects
504
505(defclass ref-counted-object (proxy)
506 ()
507 (:metaclass proxy-class))
508
509(define-type-method from-alien-form ((type ref-counted-object) form
510 &key (ref :copy))
511 (call-next-method type form :ref ref))
512
513(define-type-method from-alien-function ((type ref-counted-object)
514 &key (ref :copy))
515 (call-next-method type :ref ref))
516
4e968638 517
518;;;; Superclasses for wrapping of C structures
519
520(defclass struct (proxy)
521 ()
522 (:metaclass proxy-class)
523 (:size 0))
524
525(defmethod allocate-foreign ((struct struct) &rest initargs)
526 (declare (ignore initargs))
527 (let ((size (foreign-size (class-of struct))))
528 (if (zerop size)
529 (error "~A has zero size" (class-of struct))
530 (allocate-memory size))))
531
532
533;;;; Metaclasses used for subclasses of struct
534
535(defclass struct-class (proxy-class)
536 ())
537
538(defmethod shared-initialize ((class struct-class) names &rest initargs)
539 (declare (ignore names initargs))
540 (call-next-method)
541 (let ((offsets nil) (copy-functions nil) (destroy-functions nil))
542 (flet ((initialize-functions ()
543 (loop
544 for slotd in (class-slots class)
545 as type = (slot-definition-type slotd)
546 when (eq (slot-definition-allocation slotd) :alien)
547 do (push (slot-definition-offset slotd) offsets)
548 (push (copy-function type) copy-functions)
549 (push (destroy-function type) destroy-functions))))
550 (unless (slot-boundp class 'ref)
551 (setf
552 (slot-value class 'ref)
553 #'(lambda (from &optional (to (allocate-memory (foreign-size class))))
554 (assert (not (null-pointer-p from)))
555 (unless offsets
556 (initialize-functions))
557 (loop
558 for offset in offsets
559 for copy in copy-functions
560 do (funcall copy from to offset))
561 to)))
562 (unless (slot-boundp class 'unref)
563 (setf (slot-value class 'unref)
564 #'(lambda (location &optional inlined-p)
565 (assert (not (null-pointer-p location)))
566 (unless offsets
567 (initialize-functions))
568 (loop
569 for offset in offsets
570 for destroy in destroy-functions
571 do (funcall destroy location offset))
572 (unless inlined-p
573 (deallocate-memory location))))))))
574
575
576(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
577 (if (not (getf initargs :allocation))
578 (find-class 'direct-alien-slot-definition)
579 (call-next-method)))
580
581
582(defmethod compute-slots :around ((class struct-class))
583 (let ((slots (call-next-method)))
584 (when (and
585 #?-(or (sbcl>= 0 9 8) (featurep :clisp))(class-finalized-p class)
586 (not (slot-boundp class 'size)))
90e8bbf6 587 (setf (slot-value class 'size)
588 (or
589 (loop
590 for slotd in slots
591 when (eq (slot-definition-allocation slotd) :alien)
592 maximize (+
593 (slot-definition-offset slotd)
594 (size-of (slot-definition-type slotd))))
595 0)))
4e968638 596 slots))
597
598(define-type-method callback-wrapper ((type struct) var arg form)
599 (let ((class (type-expand type)))
600 `(let ((,var (ensure-proxy-instance ',class ,arg :finalize nil)))
601 (unwind-protect
602 ,form
603 (invalidate-instance ,var)))))
604
605(define-type-method size-of ((type struct) &key inlined)
606 (if inlined
607 (foreign-size type)
608 (size-of 'pointer)))
609
90e8bbf6 610(define-type-method type-alignment ((type struct) &key inlined)
611 (if inlined
612 (let ((slot1 (find-if
613 #'(lambda (slotd)
614 (eq (slot-definition-allocation slotd) :alien))
615 (class-slots (find-class type)))))
616 (type-alignment (slot-definition-type slot1)))
617 (type-alignment 'pointer)))
618
4e968638 619(define-type-method writer-function ((type struct) &key temp inlined)
620 (if inlined
621 (if temp
622 (let ((size (size-of type :inlined t)))
623 #'(lambda (instance location &optional (offset 0))
624 (copy-memory
625 (foreign-location instance) size
626 (pointer+ location offset))))
627 (let ((ref (reference-function (type-expand type))))
628 #'(lambda (instance location &optional (offset 0))
629 (funcall ref
630 (foreign-location instance)
631 (pointer+ location offset)))))
632 (call-next-method)))
633
634(define-type-method reader-function ((type struct) &key (ref :read) inlined)
635 (if inlined
636 (let ((class (type-expand type))
637 (size (size-of type :inlined t)))
638 (ecase ref
639 (:read
640 #'(lambda (location &optional (offset 0))
641 (ensure-proxy-instance class (pointer+ location offset))))
642 (:peek
643 #'(lambda (location &optional (offset 0))
644 (ensure-proxy-instance class (pointer+ location offset)
645 :reference nil :finalize nil)))
646 (:get
647 #'(lambda (location &optional (offset 0))
648 (prog1
649 (ensure-proxy-instance class
650 (copy-memory (pointer+ location offset) size)
651 :reference nil)
652 (clear-memory (pointer+ location offset) size))))))
653 (call-next-method)))
654
655(define-type-method destroy-function ((type struct) &key temp inlined)
656 (if inlined
657 (let ((size (size-of type :inlined t)))
658 (if temp
659 #'(lambda (location &optional (offset 0))
660 (clear-memory (pointer+ location offset) size))
661 (let ((unref (unreference-function (type-expand type))))
662 #'(lambda (location &optional (offset 0))
663 (funcall unref (pointer+ location offset) t)))))
664 (call-next-method)))
665
666(define-type-method copy-function ((type struct) &key inlined)
667 (if inlined
668 (let ((ref (reference-function (type-expand type))))
669 #'(lambda (from to &optional (offset 0))
670 (funcall ref (pointer+ from offset) (pointer+ to offset))))
671 (call-next-method)))