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