chiark / gitweb /
BUg fix
[clg] / gffi / basic-types.lisp
... / ...
CommitLineData
1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 1999-2005 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
23;; $Id: basic-types.lisp,v 1.8 2007-06-01 06:24:43 espen Exp $
24
25(in-package "GFFI")
26
27
28(deftype int ()
29 '(signed-byte #+sbcl #.(sb-sizeof-bits 'sb-alien:int)
30 #+clisp #.(ffi:bitsizeof 'ffi:int)
31 #-(or sbcl clisp) 32))
32(deftype unsigned-int ()
33 '(unsigned-byte #+sbcl #.(sb-sizeof-bits 'sb-alien:int)
34 #+clisp #.(ffi:bitsizeof 'ffi:int)
35 #-(or sbcl clisp) 32))
36(deftype long ()
37 '(signed-byte #+sbcl #.(sb-sizeof-bits 'sb-alien:long)
38 #+clisp #.(ffi:bitsizeof 'ffi:long)
39 #-(or sbcl clisp) 32))
40(deftype unsigned-long ()
41 '(unsigned-byte #+sbcl #.(sb-sizeof-bits 'sb-alien:long)
42 #+clisp #.(ffi:bitsizeof 'ffi:long)
43 #-(or sbcl clisp) 32))
44(deftype short ()
45 '(signed-byte #+sbcl #.(sb-sizeof-bits 'sb-alien:short)
46 #+clisp #.(ffi:bitsizeof 'ffi:short)
47 #-(or sbcl clisp) 16))
48(deftype unsigned-short ()
49 '(unsigned-byte #+sbcl #.(sb-sizeof-bits 'sb-alien:short)
50 #+clisp #.(ffi:bitsizeof 'ffi:short)
51 #-(or sbcl clisp) 16))
52(deftype signed (&optional (size '*)) `(signed-byte ,size))
53(deftype unsigned (&optional (size '*)) `(unsigned-byte ,size))
54(deftype char () 'base-char)
55(deftype pointer ()
56 #+(or cmu sbcl) 'system-area-pointer
57 #+clisp 'ffi:foreign-address)
58(deftype pointer-data ()
59 '(unsigned-byte #+sbcl #.(sb-sizeof-bits 'sb-alien:system-area-pointer)
60 #+clisp #.(ffi:bitsizeof 'ffi:c-pointer)
61 #-(or sbcl clisp) 32))
62
63(deftype bool (&optional (size '*)) (declare (ignore size)) 'boolean)
64(deftype copy-of (type) type)
65(deftype static (type) type)
66(deftype inlined (type) type)
67
68
69
70(define-type-generic alien-type (type)
71 "Returns the foreign type corresponding to TYPE")
72(define-type-generic size-of (type &key inlined)
73 "Returns the foreign size of TYPE. The default value of INLINED is
74T for basic C types and NIL for other types.")
75(define-type-generic type-alignment (type &key inlined)
76 "Returns the alignment of TYPE. The default value of INLINED is
77T for basic C types and NIL for other types.")
78(define-type-generic alien-arg-wrapper (type var arg style form &optional copy-p)
79 "Creates a wrapper around FORM which binds the alien translation of
80ARG to VAR in a way which makes it possible to pass the location of
81VAR in a foreign function call. It should also do any necessary clean
82up before returning the value of FORM.")
83(define-type-generic to-alien-form (type form &optional copy-p)
84 "Returns a form which translates FORM to alien representation. If
85COPY-P is non NIL then any allocated foreign memory must not be
86reclaimed later.")
87(define-type-generic from-alien-form (type form &key ref)
88 "Returns a form which translates FORM from alien to lisp
89representation. REF should be :FREE, :COPY, :STATIC or :TEMP")
90(define-type-generic to-alien-function (type &optional copy-p)
91 "Returns a function of one argument which will translate objects of the given type to alien repesentation. An optional function, taking the origional object and the alien representation as arguments, to clean up after the alien value is not needed any more may be returned as a second argument.")
92(define-type-generic from-alien-function (type &key ref)
93 "Returns a function of one argument which will translate alien objects of the given type to lisp representation. REF should be :FREE, :COPY, :STATIC or :TEMP")
94(define-type-generic callback-wrapper (type var arg form)
95 "Creates a wrapper around FORM which binds the lisp translation of
96ARG to VAR during a C callback.")
97
98(define-type-generic writer-function (type &key temp inlined)
99 "Returns a function taking a value, an address and an optional
100offset which when called will write a reference an object at the given
101location. If TEMP is non NIL then the object is expected to be valid
102as long as the reference exists.")
103(define-type-generic reader-function (type &key ref inlined)
104 "Returns a function taking an address and optional offset which when
105called will return the object at given location. REF should be :READ,
106:PEEK or :GET")
107(define-type-generic destroy-function (type &key temp inlined)
108 "Returns a function taking an address and optional offset which when
109called will destroy the reference at the given location. This may
110involve freeing the foreign object being referenced or decreasing it's
111ref. count. If TEMP is non NIL then the reference is expected to
112have been written as temporal.")
113(define-type-generic copy-function (type &key inlined))
114
115(define-type-generic unbound-value (type-spec)
116 "Returns a value which should be interpreted as unbound for slots with virtual allocation")
117
118(defun assert-inlined (type inlined-p)
119 (unless inlined-p
120 (error "Type ~A can only be inlined" type)))
121
122(defun assert-not-inlined (type inlined-p)
123 (when inlined-p
124 (error "Type ~A can not be inlined" type)))
125
126
127(define-type-method alien-arg-wrapper ((type t) var arg style form &optional
128 (copy-in-p nil copy-in-given-p))
129 (let ((alien-type (alien-type type)))
130 (cond
131 ((in-arg-p style)
132 (let ((to-alien (if copy-in-given-p
133 (to-alien-form type arg copy-in-p)
134 (to-alien-form type arg))))
135 #+(or cmu sbcl)
136 `(with-alien ((,var ,alien-type ,to-alien))
137 ,form)
138 #+clisp
139 `(ffi:with-c-var (,var ',alien-type ,to-alien)
140 ,form)))
141 ((out-arg-p style)
142 #+(or cmu sbcl)
143 `(with-alien ((,var ,alien-type))
144 (clear-memory (alien-sap (addr ,var)) ,(size-of type))
145 ,form)
146 #+clisp
147 `(ffi:with-c-var (,var ',alien-type)
148 ,form)))))
149
150(define-type-method callback-wrapper ((type t) var arg form)
151 `(let ((,var ,(from-alien-form type arg :ref :temp)))
152 ,form))
153
154(define-type-method alien-type ((type t))
155 (error "No alien type corresponding to the type specifier ~A" type))
156
157(define-type-method to-alien-form ((type t) form &optional copy-p)
158 (declare (ignore form copy-p))
159 (error "Not a valid type specifier for arguments: ~A" type))
160
161(define-type-method to-alien-function ((type t) &optional copy-p)
162 (declare (ignore copy-p))
163 (error "Not a valid type specifier for arguments: ~A" type))
164
165(define-type-method from-alien-form ((type t) form &key ref)
166 (declare (ignore form ref))
167 (error "Not a valid type specifier for return values: ~A" type))
168
169(define-type-method from-alien-function ((type t) &key ref)
170 (declare (ignore ref))
171 (error "Not a valid type specifier for return values: ~A" type))
172
173(define-type-method destroy-function ((type t) &key temp (inlined t inlined-p))
174 (declare (ignore temp))
175 (let ((size (if inlined-p
176 (size-of type :inlined inlined)
177 (size-of type))))
178 #'(lambda (location &optional (offset 0))
179 (clear-memory location size offset))))
180
181(define-type-method copy-function ((type t) &key (inlined t inlined-p))
182 (let ((size (if inlined-p
183 (size-of type :inlined inlined)
184 (size-of type))))
185 #'(lambda (from to &optional (offset 0))
186 (copy-memory (pointer+ from offset) size (pointer+ to offset)))))
187
188(define-type-method to-alien-form ((type real) form &optional copy-p)
189 (declare (ignore type copy-p))
190 form)
191
192(define-type-method to-alien-function ((type real) &optional copy-p)
193 (declare (ignore type copy-p))
194 #'identity)
195
196(define-type-method from-alien-form ((type real) form &key ref)
197 (declare (ignore type ref))
198 form)
199
200(define-type-method from-alien-function ((type real) &key ref)
201 (declare (ignore type ref))
202 #'identity)
203
204
205(define-type-method alien-type ((type integer))
206 (declare (ignore type))
207 (alien-type 'signed-byte))
208
209(define-type-method size-of ((type integer) &key (inlined t))
210 (declare (ignore type))
211 (size-of 'signed-byte :inlined inlined))
212
213(define-type-method type-alignment ((type integer) &key (inlined t))
214 (declare (ignore type))
215 (type-alignment 'signed-byte :inlined inlined))
216
217(define-type-method writer-function ((type integer) &key temp (inlined t))
218 (declare (ignore temp))
219 (assert-inlined type inlined)
220 (writer-function 'signed-byte))
221
222(define-type-method reader-function ((type integer) &key ref (inlined t))
223 (declare (ignore ref))
224 (assert-inlined type inlined)
225 (reader-function 'signed-byte))
226
227
228;;; Signed Byte
229
230(define-type-method alien-type ((type signed-byte))
231 (destructuring-bind (&optional (size '*))
232 (rest (mklist (type-expand-to 'signed-byte type)))
233 (let ((size (if (eq size '*)
234 (second (type-expand-to 'signed-byte 'int))
235 size)))
236 #+cmu
237 (ecase size
238 ( 8 '(alien:signed 8))
239 (16 '(alien:signed 16))
240 (32 '(alien:signed 32))
241 (64 '(alien:signed 64)))
242 #+sbcl
243 (ecase size
244 ( 8 '(sb-alien:signed 8))
245 (16 '(sb-alien:signed 16))
246 (32 '(sb-alien:signed 32))
247 (64 '(sb-alien:signed 64)))
248 #+clisp
249 (ecase size
250 ( 8 'ffi:sint8)
251 (16 'ffi:sint16)
252 (32 'ffi:sint32)
253 (64 'ffi:sint64)))))
254
255(define-type-method size-of ((type signed-byte) &key (inlined t))
256 (assert-inlined type inlined)
257 (destructuring-bind (&optional (size '*))
258 (rest (mklist (type-expand-to 'signed-byte type)))
259 (let ((size (if (eq size '*)
260 (second (type-expand-to 'signed-byte 'int))
261 size)))
262 (ecase size
263 ( 8 1)
264 (16 2)
265 (32 4)
266 (64 8)))))
267
268(define-type-method type-alignment ((type signed-byte) &key (inlined t))
269 (assert-inlined type inlined)
270 (destructuring-bind (&optional (size '*))
271 (rest (mklist (type-expand-to 'signed-byte type)))
272 (let ((size (if (eq size '*)
273 (second (type-expand-to 'signed-byte 'int))
274 size)))
275 #+sbcl(sb-alignment `(sb-alien:signed ,size))
276 #+clisp(ecase size
277 ( 8 (nth-value 1 (ffi:sizeof 'ffi:sint8)))
278 (16 (nth-value 1 (ffi:sizeof 'ffi:sint16)))
279 (32 (nth-value 1 (ffi:sizeof 'ffi:sint32)))
280 (64 (nth-value 1 (ffi:sizeof 'ffi:sint64))))
281 #-(or sbcl clisp) 4)))
282
283(define-type-method writer-function ((type signed-byte) &key temp (inlined t))
284 (declare (ignore temp))
285 (assert-inlined type inlined)
286 (destructuring-bind (&optional (size '*))
287 (rest (mklist (type-expand-to 'signed-byte type)))
288 (let ((size (if (eq size '*)
289 (second (type-expand-to 'signed-byte 'int))
290 size)))
291 (ecase size
292 ( 8 #'(lambda (value location &optional (offset 0))
293 (setf
294 #+(or cmu sbcl)(signed-sap-ref-8 location offset)
295 #+clisp(ffi:memory-as location 'ffi:sint8 offset)
296 value)))
297 (16 #'(lambda (value location &optional (offset 0))
298 (setf
299 #+(or cmu sbcl)(signed-sap-ref-16 location offset)
300 #+clisp(ffi:memory-as location 'ffi:sint16 offset)
301 value)))
302 (32 #'(lambda (value location &optional (offset 0))
303 (setf
304 #+(or cmu sbcl)(signed-sap-ref-32 location offset)
305 #+clisp(ffi:memory-as location 'ffi:sint32 offset)
306 value)))
307 (64 #'(lambda (value location &optional (offset 0))
308 (setf
309 #+(or cmu sbcl)(signed-sap-ref-64 location offset)
310 #+clisp(ffi:memory-as location 'ffi:sint64 offset)
311 value)))))))
312
313(define-type-method reader-function ((type signed-byte) &key ref (inlined t))
314 (declare (ignore ref))
315 (assert-inlined type inlined)
316 (destructuring-bind (&optional (size '*))
317 (rest (mklist (type-expand-to 'signed-byte type)))
318 (let ((size (if (eq size '*)
319 (second (type-expand-to 'signed-byte 'int))
320 size)))
321 (ecase size
322 ( 8 #'(lambda (location &optional (offset 0))
323 #+(or cmu sbcl)(signed-sap-ref-8 location offset)
324 #+clisp(ffi:memory-as location 'ffi:sint8 offset)))
325 (16 #'(lambda (location &optional (offset 0))
326 #+(or cmu sbcl)(signed-sap-ref-16 location offset)
327 #+clisp(ffi:memory-as location 'ffi:sint16 offset)))
328 (32 #'(lambda (location &optional (offset 0))
329 #+(or cmu sbcl)(signed-sap-ref-32 location offset)
330 #+clisp(ffi:memory-as location 'ffi:sint32 offset)))
331 (64 #'(lambda (location &optional (offset 0))
332 #+(or cmu sbcl)(signed-sap-ref-64 location offset)
333 #+clisp(ffi:memory-as location 'ffi:sint64 offset)))))))
334
335
336
337;;; Unsigned Byte
338
339(define-type-method alien-type ((type unsigned-byte))
340 (destructuring-bind (&optional (size '*))
341 (rest (mklist (type-expand-to 'unsigned-byte type)))
342 (let ((size (if (eq size '*)
343 (second (type-expand-to 'signed-byte 'int))
344 size)))
345 #+cmu
346 (ecase size
347 ( 8 '(alien:unsigned 8))
348 (16 '(alien:unsigned 16))
349 (32 '(alien:unsigned 32))
350 (64 '(alien:unsigned 64)))
351 #+sbcl
352 (ecase size
353 ( 8 '(sb-alien:unsigned 8))
354 (16 '(sb-alien:unsigned 16))
355 (32 '(sb-alien:unsigned 32))
356 (64 '(sb-alien:unsigned 64)))
357 #+clisp
358 (ecase size
359 ( 8 'ffi:uint8)
360 (16 'ffi:uint16)
361 (32 'ffi:uint32)
362 (64 'ffi:uint64)))))
363
364(define-type-method size-of ((type unsigned-byte) &key (inlined t))
365 (assert-inlined type inlined)
366 (destructuring-bind (&optional (size '*))
367 (rest (mklist (type-expand-to 'unsigned-byte type)))
368 (size-of `(signed ,size))))
369
370(define-type-method type-alignment ((type unsigned-byte) &key (inlined t))
371 (assert-inlined type inlined)
372 (destructuring-bind (&optional (size '*))
373 (rest (mklist (type-expand-to 'unsigned-byte type)))
374 (type-alignment `(signed ,size))))
375
376(define-type-method writer-function ((type unsigned-byte) &key temp (inlined t))
377 (declare (ignore temp))
378 (assert-inlined type inlined)
379 (destructuring-bind (&optional (size '*))
380 (rest (mklist (type-expand-to 'unsigned-byte type)))
381 (let ((size (if (eq size '*)
382 (second (type-expand-to 'signed-byte 'int))
383 size)))
384 (ecase size
385 ( 8 #'(lambda (value location &optional (offset 0))
386 (setf
387 #+(or cmu sbcl)(sap-ref-8 location offset)
388 #+clisp(ffi:memory-as location 'ffi:uint8 offset)
389 value)))
390 (16 #'(lambda (value location &optional (offset 0))
391 (setf
392 #+(or cmu sbcl)(sap-ref-16 location offset)
393 #+clisp(ffi:memory-as location 'ffi:uint16 offset)
394 value)))
395 (32 #'(lambda (value location &optional (offset 0))
396 (setf
397 #+(or cmu sbcl)(sap-ref-32 location offset)
398 #+clisp(ffi:memory-as location 'ffi:uint32 offset)
399 value)))
400 (64 #'(lambda (value location &optional (offset 0))
401 (setf
402 #+(or cmu sbcl)(sap-ref-64 location offset)
403 #+clisp(ffi:memory-as location 'ffi:uint64 offset)
404 value)))))))
405
406(define-type-method reader-function ((type unsigned-byte) &key ref (inlined t))
407 (declare (ignore ref))
408 (assert-inlined type inlined)
409 (destructuring-bind (&optional (size '*))
410 (rest (mklist (type-expand-to 'unsigned-byte type)))
411 (let ((size (if (eq size '*)
412 (second (type-expand-to 'signed-byte 'int))
413 size)))
414 (ecase size
415 ( 8 #'(lambda (location &optional (offset 0))
416 #+(or cmu sbcl)(sap-ref-8 location offset)
417 #+clisp(ffi:memory-as location 'ffi:uint8 offset)))
418 (16 #'(lambda (location &optional (offset 0))
419 #+(or cmu sbcl)(sap-ref-16 location offset)
420 #+clisp(ffi:memory-as location 'ffi:uint16 offset)))
421 (32 #'(lambda (location &optional (offset 0))
422 #+(or cmu sbcl)(sap-ref-32 location offset)
423 #+clisp(ffi:memory-as location 'ffi:uint32 offset)))
424 (64 #'(lambda (location &optional (offset 0))
425 #+(or cmu sbcl)(sap-ref-64 location offset)
426 #+clisp(ffi:memory-as location 'ffi:uint64 offset)))))))
427
428
429
430;;; Single Float
431
432(define-type-method alien-type ((type single-float))
433 (declare (ignore type))
434 #+cmu 'alien:single-float
435 #+sbcl 'sb-alien:single-float
436 #+clisp 'single-float)
437
438(define-type-method size-of ((type single-float) &key (inlined t))
439 (assert-inlined type inlined)
440 #+sbcl (sb-sizeof 'sb-alien:float)
441 #+clisp (ffi:sizeof 'single-float)
442 #-(or sbcl clisp) 4)
443
444(define-type-method type-alignment ((type single-float) &key (inlined t))
445 (assert-inlined type inlined)
446 #+sbcl (sb-alignment 'single-float)
447 #+clisp (nth-value 1 (ffi:sizeof 'single-float))
448 #-(or sbcl clisp) 4)
449
450(define-type-method to-alien-form ((type single-float) form &optional copy-p)
451 (declare (ignore type copy-p))
452 `(coerce ,form 'single-float))
453
454(define-type-method to-alien-function ((type single-float) &optional copy-p)
455 (declare (ignore type copy-p))
456 #'(lambda (number)
457 (coerce number 'single-float)))
458
459(define-type-method writer-function ((type single-float) &key temp (inlined t))
460 (declare (ignore temp))
461 (assert-inlined type inlined)
462 #'(setf ref-single-float))
463
464(define-type-method reader-function ((type single-float) &key ref (inlined t))
465 (declare (ignore ref))
466 (assert-inlined type inlined)
467 #'ref-single-float)
468
469
470
471;;; Double Float
472
473(define-type-method alien-type ((type double-float))
474 (declare (ignore type))
475 #+cmu 'alien:double-float
476 #+sbcl 'sb-alien:double-float
477 #+clisp 'double-float)
478
479(define-type-method size-of ((type double-float) &key (inlined t))
480 (assert-inlined type inlined)
481 #+sbcl (sb-sizeof 'sb-alien:double)
482 #+clisp (ffi:sizeof 'double-float)
483 #-(or sbcl clisp) 8)
484
485(define-type-method type-alignment ((type double-float) &key (inlined t))
486 (assert-inlined type inlined)
487 #+sbcl (sb-alignment 'double-float)
488 #+clisp (nth-value 1 (ffi:sizeof 'double-float))
489 #-(or sbcl clisp) 4)
490
491(define-type-method to-alien-form ((type double-float) form &optional copy-p)
492 (declare (ignore type copy-p))
493 `(coerce ,form 'double-float))
494
495(define-type-method to-alien-function ((type double-float) &optional copy-p)
496 (declare (ignore type copy-p))
497 #'(lambda (number)
498 (coerce number 'double-float)))
499
500(define-type-method writer-function ((type double-float) &key temp (inlined t))
501 (declare (ignore temp))
502 (assert-inlined type inlined)
503 #'(lambda (value location &optional (offset 0))
504 (setf (ref-double-float location offset) (coerce value 'double-float))))
505
506(define-type-method reader-function ((type double-float) &key ref (inlined t))
507 (declare (ignore ref))
508 (assert-inlined type inlined)
509 #'ref-double-float)
510
511(deftype optimized-double-float () 'double-float)
512
513(define-type-method to-alien-form ((type optimized-double-float) form &optional copy-p)
514 (declare (ignore type copy-p))
515 form)
516
517
518
519;;; Character
520
521(define-type-method alien-type ((type base-char))
522 (declare (ignore type))
523 #+cmu 'c-call:char
524 #+sbcl 'sb-alien:char
525 #+clisp 'ffi:character)
526
527(define-type-method size-of ((type base-char) &key (inlined t))
528 (assert-inlined type inlined)
529 1)
530
531(define-type-method type-alignment ((type base-char) &key (inlined t))
532 (assert-inlined type inlined)
533 #+sbcl (sb-alignment 'sb-alien:char)
534 #+clisp (nth-value 1 (ffi:sizeof 'ffi:character))
535 #-(or sbcl clisp) 4)
536
537(define-type-method to-alien-form ((type base-char) form &optional copy-p)
538 (declare (ignore type copy-p))
539 form)
540
541(define-type-method to-alien-function ((type base-char) &optional copy-p)
542 (declare (ignore type copy-p))
543 #'identity)
544
545(define-type-method from-alien-form ((type base-char) form &key ref)
546 (declare (ignore type ref))
547 form)
548
549(define-type-method from-alien-function ((type base-char) &key ref)
550 (declare (ignore type ref))
551 #'identity)
552
553(define-type-method writer-function ((type base-char) &key temp (inlined t))
554 (declare (ignore temp))
555 (assert-inlined type inlined)
556 #'(lambda (char location &optional (offset 0))
557 #+(or cmu sbcl)
558 (setf (sap-ref-8 location offset) (char-code char))
559 #+clisp(setf (ffi:memory-as location 'ffi:character offset) char)))
560
561(define-type-method reader-function ((type base-char) &key ref (inlined t))
562 (declare (ignore ref))
563 (assert-inlined type inlined)
564 #'(lambda (location &optional (offset 0))
565 #+(or cmu sbcl)(code-char (sap-ref-8 location offset))
566 #+clisp(ffi:memory-as location 'ffi:character offset)))
567
568
569
570;;; String
571
572(defun utf8-length (string)
573 "Returns the length including the trailing zero, of STRING encoded as UTF8"
574 (1+ (loop
575 for char across string
576 as char-code = (char-code char)
577 sum (cond
578 ((< char-code #x7F) 1)
579 ((< char-code #x7FF) 2)
580 ((< char-code #xFFFF) 3)
581 ((< char-code #x1FFFFF) 4)))))
582
583(defun encode-utf8-string (string &optional location)
584 (let* ((len (utf8-length string))
585 (location (or location (allocate-memory len))))
586 (loop
587 for char across string
588 for i from 0
589 as char-code = (char-code char)
590 do (flet ((encode (size)
591 (let ((rem (mod size 6)))
592 (setf (ref-byte location i)
593 (deposit-field
594 #xFF (byte (- 7 rem) (1+ rem))
595 (ldb (byte rem (- size rem)) char-code)))
596 (loop
597 for pos from (- size rem 6) downto 0 by 6
598 do (setf (ref-byte location (incf i))
599 (+ 128 (ldb (byte 6 pos) char-code)))))))
600 (cond
601 ((< char-code #x80) (setf (ref-byte location i) char-code))
602 ((< char-code #x800) (encode 11))
603 ((< char-code #x10000) (encode 16))
604 ((< char-code #x200000) (encode 21)))))
605 (setf (ref-byte location (1- len)) 0)
606 location))
607
608(defun decode-utf8-string (c-string)
609 (with-output-to-string (string)
610 (loop
611 for i from 0
612 as octet = (ref-byte c-string i)
613 until (zerop octet)
614 do (flet ((decode (size)
615 (loop
616 with rem = (mod size 6)
617 for pos from (- size rem) downto 0 by 6
618 as code = (dpb (ldb (byte rem 0) octet) (byte rem pos) 0)
619 then (dpb
620 (ldb (byte 6 0) (ref-byte c-string (incf i)))
621 (byte 6 pos) code)
622 finally (write-char (code-char code) string))))
623 (cond
624 ((< octet 128) (write-char (code-char octet) string))
625 ((< octet 224) (decode 11))
626 ((< octet 240) (decode 16))
627 ((< octet 248) (decode 21)))))))
628
629
630(define-type-method alien-arg-wrapper ((type string) var string style form &optional copy-in-p)
631 (declare (ignore type))
632 (cond
633 ((and (in-arg-p style) copy-in-p)
634 `(with-pointer (,var (encode-utf8-string ,string))
635 ,form))
636 ((and (in-arg-p style) (not (out-arg-p style)))
637 `(with-memory (,var (utf8-length ,string))
638 (encode-utf8-string ,string ,var)
639 ,form))
640 ((and (in-arg-p style) (out-arg-p style))
641 (let ((c-string (make-symbol "C-STRING")))
642 `(with-memory (,c-string (utf8-length ,string))
643 (encode-utf8-string ,string ,c-string)
644 (with-pointer (,var ,c-string)
645 ,form))))
646 ((and (out-arg-p style) (not (in-arg-p style)))
647 `(with-pointer (,var)
648 ,form))))
649
650(define-type-method alien-type ((type string))
651 (declare (ignore type))
652 (alien-type 'pointer))
653
654(define-type-method size-of ((type string) &key inlined)
655 (assert-not-inlined type inlined)
656 (size-of 'pointer))
657
658(define-type-method type-alignment ((type string) &key inlined)
659 (assert-not-inlined type inlined)
660 (type-alignment 'pointer))
661
662(define-type-method to-alien-form ((type string) string &optional copy-p)
663 (declare (ignore type copy-p))
664 `(encode-utf8-string ,string))
665
666(define-type-method to-alien-function ((type string) &optional copy-p)
667 (declare (ignore type))
668 (values
669 #'encode-utf8-string
670 (unless copy-p
671 #'(lambda (string c-string)
672 (declare (ignore string))
673 (deallocate-memory c-string)))))
674
675(define-type-method from-alien-form ((type string) form &key (ref :free))
676 (declare (ignore type))
677 `(let ((c-string ,form))
678 (unless (null-pointer-p c-string)
679 (prog1
680 (decode-utf8-string c-string)
681 ,(when (eq ref :free)
682 `(deallocate-memory c-string))))))
683
684(define-type-method from-alien-function ((type string) &key (ref :free))
685 (declare (ignore type))
686 (if (eq ref :free)
687 #'(lambda (c-string)
688 (unless (null-pointer-p c-string)
689 (prog1
690 (decode-utf8-string c-string)
691 (deallocate-memory c-string))))
692 #'(lambda (c-string)
693 (unless (null-pointer-p c-string)
694 (decode-utf8-string c-string)))))
695
696(define-type-method writer-function ((type string) &key temp inlined)
697 (declare (ignore temp))
698 (assert-not-inlined type inlined)
699 #'(lambda (string location &optional (offset 0))
700 (assert (null-pointer-p (ref-pointer location offset)))
701 (setf (ref-pointer location offset) (encode-utf8-string string))))
702
703(define-type-method reader-function ((type string) &key (ref :read) inlined)
704 (assert-not-inlined type inlined)
705 (ecase ref
706 ((:read :peek)
707 #'(lambda (location &optional (offset 0))
708 (unless (null-pointer-p (ref-pointer location offset))
709 (decode-utf8-string (ref-pointer location offset)))))
710 (:get
711 #'(lambda (location &optional (offset 0))
712 (unless (null-pointer-p (ref-pointer location offset))
713 (prog1
714 (decode-utf8-string (ref-pointer location offset))
715 (deallocate-memory (ref-pointer location offset))
716 (setf (ref-pointer location offset) (make-pointer 0))))))))
717
718(define-type-method destroy-function ((type string) &key temp inlined)
719 (declare (ignore temp))
720 (assert-not-inlined type inlined)
721 #'(lambda (location &optional (offset 0))
722 (unless (null-pointer-p (ref-pointer location offset))
723 (deallocate-memory (ref-pointer location offset))
724 (setf (ref-pointer location offset) (make-pointer 0)))))
725
726(define-type-method copy-function ((type string) &key inlined)
727 (assert-not-inlined type inlined)
728 (lambda (from to &optional (offset 0))
729 (let* ((string (ref-pointer from offset))
730 (length (loop
731 for i from 0
732 until (zerop (ref-byte string i))
733 finally (return (1+ i)))))
734 (setf (ref-pointer to offset) (copy-memory string length)))))
735
736(define-type-method unbound-value ((type string))
737 (declare (ignore type))
738 nil)
739
740
741
742;;; Pathname
743
744(define-type-method alien-type ((type pathname))
745 (declare (ignore type))
746 (alien-type 'string))
747
748(define-type-method size-of ((type pathname) &key inlined)
749 (assert-not-inlined type inlined)
750 (size-of 'string))
751
752(define-type-method type-alignment ((type pathname) &key inlined)
753 (assert-not-inlined type inlined)
754 (type-alignment 'string))
755
756(define-type-method alien-arg-wrapper ((type pathname) var pathname style form &optional copy-in-p)
757 (declare (ignore type))
758 (alien-arg-wrapper 'string var `(namestring (translate-logical-pathname ,pathname)) style form copy-in-p))
759
760(define-type-method to-alien-form ((type pathname) path)
761 (declare (ignore type))
762 (to-alien-form 'string `(namestring (translate-logical-pathname ,path))))
763
764(define-type-method to-alien-function ((type pathname) &optional copy-p)
765 (declare (ignore type))
766 (let ((string-function (to-alien-function 'string copy-p)))
767 #'(lambda (path)
768 (funcall string-function (namestring path)))))
769
770(define-type-method from-alien-form ((type pathname) form &key (ref :free))
771 (declare (ignore type))
772 `(parse-namestring ,(from-alien-form 'string form :ref ref)))
773
774(define-type-method from-alien-function ((type pathname) &key (ref :free))
775 (declare (ignore type))
776 (let ((string-function (from-alien-function 'string :ref ref)))
777 #'(lambda (string)
778 (parse-namestring (funcall string-function string)))))
779
780(define-type-method writer-function ((type pathname) &key temp inlined)
781 (declare (ignore temp))
782 (assert-not-inlined type inlined)
783 (let ((string-writer (writer-function 'string)))
784 #'(lambda (path location &optional (offset 0))
785 (funcall string-writer (namestring path) location offset))))
786
787(define-type-method reader-function ((type pathname) &key ref inlined)
788 (declare (ignore ref))
789 (assert-not-inlined type inlined)
790 (let ((string-reader (reader-function 'string)))
791 #'(lambda (location &optional (offset 0))
792 (let ((string (funcall string-reader location offset)))
793 (when string
794 (parse-namestring string))))))
795
796(define-type-method destroy-function ((type pathname) &key temp inlined)
797 (declare (ignore temp))
798 (assert-not-inlined type inlined)
799 (destroy-function 'string))
800
801(define-type-method copy-function ((type pathname) &key inlined)
802 (assert-not-inlined type inlined)
803 (copy-function 'string))
804
805(define-type-method unbound-value ((type pathname))
806 (declare (ignore type))
807 (unbound-value 'string))
808
809
810
811;;; Bool
812
813(define-type-method alien-type ((type bool))
814 (destructuring-bind (&optional (size '*))
815 (rest (mklist (type-expand-to 'bool type)))
816 (alien-type `(signed-byte ,size))))
817
818(define-type-method size-of ((type bool) &key (inlined t))
819 (assert-inlined type inlined)
820 (destructuring-bind (&optional (size '*))
821 (rest (mklist (type-expand-to 'bool type)))
822 (size-of `(signed-byte ,size))))
823
824(define-type-method type-alignment ((type bool) &key (inlined t))
825 (assert-inlined type inlined)
826 (destructuring-bind (&optional (size '*))
827 (rest (mklist (type-expand-to 'bool type)))
828 (type-alignment `(signed-byte ,size))))
829
830(define-type-method to-alien-form ((type bool) bool &optional copy-p)
831 (declare (ignore type copy-p))
832 `(if ,bool 1 0))
833
834(define-type-method to-alien-function ((type bool) &optional copy-p)
835 (declare (ignore type copy-p))
836 #'(lambda (bool)
837 (if bool 1 0)))
838
839(define-type-method from-alien-form ((type bool) form &key ref)
840 (declare (ignore type ref))
841 `(not (zerop ,form)))
842
843(define-type-method from-alien-function ((type bool) &key ref)
844 (declare (ignore type ref))
845 #'(lambda (bool)
846 (not (zerop bool))))
847
848(define-type-method writer-function ((type bool) &key temp (inlined t))
849 (declare (ignore temp))
850 (assert-inlined type inlined)
851 (destructuring-bind (&optional (size '*))
852 (rest (mklist (type-expand-to 'bool type)))
853 (let ((writer (writer-function `(signed-byte ,size))))
854 #'(lambda (bool location &optional (offset 0))
855 (funcall writer (if bool 1 0) location offset)))))
856
857(define-type-method reader-function ((type bool) &key ref (inlined t))
858 (declare (ignore ref))
859 (assert-inlined type inlined)
860 (destructuring-bind (&optional (size '*))
861 (rest (mklist (type-expand-to 'bool type)))
862 (let ((reader (reader-function `(signed-byte ,size))))
863 #'(lambda (location &optional (offset 0))
864 (not (zerop (funcall reader location offset)))))))
865
866
867
868;;; Boolean
869
870(define-type-method alien-type ((type boolean))
871 (declare (ignore type))
872 (alien-type 'bool))
873
874(define-type-method size-of ((type boolean) &key (inlined t))
875 (assert-inlined type inlined)
876 (size-of 'bool))
877
878(define-type-method type-alignment ((type boolean) &key (inlined t))
879 (assert-inlined type inlined)
880 (type-alignment 'bool))
881
882(define-type-method to-alien-form ((type boolean) boolean &optional copy-p)
883 (declare (ignore type copy-p))
884 (to-alien-form 'bool boolean))
885
886(define-type-method to-alien-function ((type boolean) &optional copy-p)
887 (declare (ignore type copy-p))
888 (to-alien-function 'bool))
889
890(define-type-method from-alien-form ((type boolean) form &key ref)
891 (declare (ignore type ref))
892 (from-alien-form 'bool form))
893
894(define-type-method from-alien-function ((type boolean) &key ref)
895 (declare (ignore type ref))
896 (from-alien-function 'bool))
897
898(define-type-method writer-function ((type boolean) &key temp (inlined t))
899 (declare (ignore temp))
900 (assert-inlined type inlined)
901 (writer-function 'bool))
902
903(define-type-method reader-function ((type boolean) &key ref (inlined t))
904 (declare (ignore ref))
905 (assert-inlined type inlined)
906 (reader-function 'bool))
907
908
909;;; Or
910
911(define-type-method alien-type ((type or))
912 (let* ((expanded-type (type-expand-to 'or type))
913 (alien-type (alien-type (second expanded-type))))
914 (unless (every #'(lambda (type)
915 (eq alien-type (alien-type type)))
916 (cddr expanded-type))
917 (error "No common alien type specifier for union type: ~A" type))
918 alien-type))
919
920(define-type-method size-of ((type or) &key (inlined nil inlined-p))
921 (loop
922 for subtype in (type-expand-to 'or type)
923 maximize (if inlined-p
924 (size-of subtype inlined)
925 (size-of subtype))))
926
927(define-type-method type-alignment ((type or) &key (inlined nil inlined-p))
928 (loop
929 for subtype in (type-expand-to 'or type)
930 maximize (if inlined-p
931 (type-alignment subtype inlined)
932 (type-alignment subtype))))
933
934(define-type-method alien-arg-wrapper ((type or) var value style form &optional copy-in-p)
935 (cond
936 ((and (in-arg-p style) (out-arg-p style))
937 `(etypecase ,value
938 ,@(mapcar
939 #'(lambda (type)
940 `(,type ,(alien-arg-wrapper type var value style form copy-in-p)))
941 (rest (type-expand-to 'or type)))))
942 ((in-arg-p style)
943 (let ((body (make-symbol "BODY")))
944 `(flet ((,body (,var)
945 ,form))
946 (etypecase ,value
947 ,@(mapcar
948 #'(lambda (type)
949 `(,type ,(alien-arg-wrapper type var value style `(,body ,var) copy-in-p)))
950 (rest (type-expand-to 'or type)))))))
951 ((out-arg-p style)
952 #+(or cmu sbcl)
953 `(with-alien ((,var ,(alien-type type)))
954 (clear-memory (alien-sap (addr ,var)) ,(size-of type))
955 ,form)
956 #+clisp
957 `(ffi:with-c-var (,var ',(alien-type type))
958 ,form))))
959
960(define-type-method to-alien-form ((type or) form &optional copy-p)
961 `(let ((value ,form))
962 (etypecase value
963 ,@(mapcar
964 #'(lambda (type)
965 `(,type ,(to-alien-form type 'value copy-p)))
966 (rest (type-expand-to 'or type))))))
967
968(define-type-method to-alien-function ((type or) &optional copy-p)
969 (let* ((expanded-type (type-expand-to 'or type))
970 (functions (loop
971 for type in (rest expanded-type)
972 collect (to-alien-function type copy-p))))
973 #'(lambda (value)
974 (loop
975 for function in functions
976 for alt-type in (rest expanded-type)
977 when (typep value alt-type)
978 do (return (funcall function value))
979 finally (error "~S is not of type ~A" value type)))))
980
981
982;;; Pointer
983
984(define-type-method alien-type ((type pointer))
985 (declare (ignore type))
986 #+(or cmu sbcl) 'system-area-pointer
987 #+clisp 'ffi:c-pointer)
988
989(define-type-method size-of ((type pointer) &key (inlined t))
990 (assert-inlined type inlined)
991 #+sbcl (sb-sizeof 'sb-alien:system-area-pointer)
992 #+clisp (ffi:sizeof 'ffi:c-pointer)
993 #-(or sbcl clisp) 4)
994
995(define-type-method type-alignment ((type pointer) &key (inlined t))
996 (assert-inlined type inlined)
997 #+sbcl (sb-alignment 'system-area-pointer)
998 #+clisp (ffi:sizeof 'ffi:c-pointer)
999 #-(or sbcl clisp) (size-of 'pointer))
1000
1001(define-type-method to-alien-form ((type pointer) form &optional copy-p)
1002 (declare (ignore type copy-p))
1003 form)
1004
1005(define-type-method to-alien-function ((type pointer) &optional copy-p)
1006 (declare (ignore type copy-p))
1007 #'identity)
1008
1009(define-type-method from-alien-form ((type pointer) form &key ref)
1010 (declare (ignore type ref))
1011 form)
1012
1013(define-type-method from-alien-function ((type pointer) &key ref)
1014 (declare (ignore type ref))
1015 #'identity)
1016
1017(define-type-method writer-function ((type pointer) &key temp (inlined t))
1018 (declare (ignore temp))
1019 (assert-inlined type inlined)
1020 #'(setf ref-pointer))
1021
1022(define-type-method reader-function ((type pointer) &key ref (inlined t))
1023 (declare (ignore ref))
1024 (assert-inlined type inlined)
1025 #'ref-pointer)
1026
1027
1028(define-type-method alien-type ((type null))
1029 (declare (ignore type))
1030 (alien-type 'pointer))
1031
1032(define-type-method size-of ((type null) &key (inlined t))
1033 (assert-inlined type inlined)
1034 (size-of 'pointer))
1035
1036(define-type-method to-alien-form ((type null) null &optional copy-p)
1037 (declare (ignore type copy-p))
1038 `(progn ,null (make-pointer 0)))
1039
1040(define-type-method to-alien-function ((type null) &optional copy-p)
1041 (declare (ignore type copy-p))
1042 #'(lambda (null)
1043 (declare (ignore null))
1044 (make-pointer 0)))
1045
1046
1047(define-type-method alien-type ((type nil))
1048 (declare (ignore type))
1049 #+(or cmu sbcl) 'void
1050 #+clisp nil)
1051
1052(define-type-method from-alien-form ((type nil) form &key ref)
1053 (declare (ignore type ref))
1054 form)
1055
1056(define-type-method from-alien-function ((type nil) &key ref)
1057 (declare (ignore type ref))
1058 #'(lambda (value)
1059 (declare (ignore value))
1060 (values)))
1061
1062(define-type-method to-alien-form ((type nil) form &optional copy-p)
1063 (declare (ignore type copy-p))
1064 form)
1065
1066
1067
1068;;; Callbacks
1069
1070(define-type-method alien-type ((type callback))
1071 (declare (ignore type))
1072 (alien-type 'pointer))
1073
1074(define-type-method to-alien-form ((type callback) callback &optional copy-p)
1075 (declare (ignore type copy-p))
1076 `(callback-address ,callback))
1077
1078
1079
1080;;; Copy-of
1081
1082(define-type-method from-alien-form ((type copy-of) form &key (ref :copy))
1083 (if (eq ref :copy)
1084 (from-alien-form (second (type-expand-to 'copy-of type)) form :ref ref)
1085 (error "Keyword arg :REF to FROM-ALIEN-FORM should be :COPY for type ~A. It was give ~A" type ref)))
1086
1087(define-type-method from-alien-function ((type copy-of) &key (ref :copy))
1088 (if (eq ref :copy)
1089 (from-alien-function (second (type-expand-to 'copy-of type)) :ref ref)
1090 (error "Keyword arg :REF to FROM-ALIEN-FUNCTION should be :COPY for type ~A. It was give ~A" type ref)))
1091
1092(define-type-method to-alien-form ((type copy-of) form &optional (copy-p t))
1093 (if copy-p
1094 (to-alien-form (second (type-expand-to 'copy-of type)) form t)
1095 (error "COPY-P argument to TO-ALIEN-FORM should always be non NIL for type ~A" type)))
1096
1097(define-type-method to-alien-function ((type copy-of) &optional (copy-p t))
1098 (if copy-p
1099 (to-alien-function (second (type-expand-to 'copy-of type)) t)
1100 (error "COPY-P argument to TO-ALIEN-FUNCTION should always be non NIL for type ~A" type)))
1101
1102(define-type-method reader-function ((type copy-of) &key (ref :read) (inlined nil inlined-p))
1103 (if inlined-p
1104 (reader-function (second (type-expand-to 'copy-of type))
1105 :ref (if (eq ref :get) :read ref) :inlined inlined)
1106 (reader-function (second (type-expand-to 'copy-of type))
1107 :ref (if (eq ref :get) :read ref))))
1108
1109(define-type-method destroy-function ((type copy-of) &key temp inlined)
1110 (declare (ignore type temp inlined))
1111 #'(lambda (location &optional offset)
1112 (declare (ignore location offset))))
1113
1114(define-type-method copy-function ((type copy-of) &key (inlined nil inlined-p))
1115 (let ((size (if inlined-p
1116 (size-of type :inlined inlined)
1117 (size-of type))))
1118 #'(lambda (from to &optional (offset 0))
1119 (copy-memory (pointer+ from offset) size (pointer+ to offset)))))
1120
1121
1122
1123;;; Static
1124
1125(define-type-method from-alien-form ((type static) form &key (ref :static))
1126 (if (eq ref :static)
1127 (from-alien-form (second (type-expand-to 'static type)) form :ref ref)
1128 (error "Keyword arg :REF to FROM-ALIEN-FORM should be :STATIC for type ~A. It was give ~A" type ref)))
1129
1130(define-type-method from-alien-function ((type static) &key (ref :static))
1131 (if (eq ref :static)
1132 (from-alien-function (second (type-expand-to 'static type)) :ref ref)
1133 (error "Keyword arg :REF to FROM-ALIEN-FUNCTION should be :STATIC for type ~A. It was give ~A" type ref)))
1134
1135(define-type-method to-alien-function ((type static) &optional copy-p)
1136 (if (not copy-p)
1137 (to-alien-function (second (type-expand-to 'static type)) t)
1138 (error "COPY-P argument to TO-ALIEN-FUNCTION should always be NIL for type ~A" type)))
1139
1140(define-type-method to-alien-form ((type static) &optional copy-p)
1141 (if (not copy-p)
1142 (to-alien-form (second (type-expand-to 'static type)) t)
1143 (error "COPY-P argument to TO-ALIEN-FORM should always be NIL for type ~A" type)))
1144
1145(define-type-method reader-function ((type static) &key (ref :read) (inlined nil inlined-p))
1146 (if inlined-p
1147 (reader-function (second (type-expand-to 'static type))
1148 :ref (if (eq ref :get) :read ref) :inlined inlined)
1149 (reader-function (second (type-expand-to 'static type))
1150 :ref (if (eq ref :get) :read ref))))
1151
1152(define-type-method writer-function ((type static) &key temp inlined)
1153 (declare (ignore type temp inlined))
1154 (error "Can't overwrite a static (const) reference"))
1155
1156(define-type-method destroy-function ((type static) &key temp inlined)
1157 (declare (ignore type temp inlined))
1158 #'(lambda (location &optional offset)
1159 (declare (ignore location offset))))
1160
1161(define-type-method copy-function ((type static) &key (inlined nil inlined-p))
1162 (let ((size (if inlined-p
1163 (size-of type :inlined inlined)
1164 (size-of type))))
1165 #'(lambda (from to &optional (offset 0))
1166 (copy-memory (pointer+ from offset) size (pointer+ to offset)))))
1167
1168
1169
1170;;; Pseudo type for inlining of types which are not inlined by default
1171
1172(define-type-method size-of ((type inlined) &key (inlined t))
1173 (assert-inlined type inlined)
1174 (size-of (second (type-expand-to 'inlined type)) :inlined t))
1175
1176(define-type-method type-alignment ((type inlined) &key (inlined t))
1177 (assert-inlined type inlined)
1178 (type-alignment (second (type-expand-to 'inlined type)) :inlined t))
1179
1180(define-type-method reader-function ((type inlined) &key (ref :read) (inlined t))
1181 (assert-inlined type inlined)
1182 (reader-function (second (type-expand-to 'inlined type)) :ref ref :inlined t))
1183
1184(define-type-method writer-function ((type inlined) &key temp (inlined t))
1185 (assert-inlined type inlined)
1186 (writer-function (second (type-expand-to 'inlined type)) :temp temp :inlined t))
1187
1188(define-type-method destroy-function ((type inlined) &key temp (inlined t))
1189 (assert-inlined type inlined)
1190 (destroy-function (second (type-expand-to 'inlined type)) :temp temp :inlined t))
1191
1192(define-type-method copy-function ((type inlined) &key (inlined t))
1193 (assert-inlined type inlined)
1194 (copy-function (second (type-expand-to 'inlined type)) :inlined t))