forked from borodust/claw-utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclaw-utils.lisp
127 lines (95 loc) · 3.88 KB
/
claw-utils.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
(cl:defpackage :claw-utils
(:use :cl :alexandria)
(:export #:claw-pointer
#:claw-string
#:claw-array
#:define-bitfield-from-enum
#:define-bitfield-from-constants))
(cl:in-package :claw-utils)
;;;
;;; CLAW POINTER
;;;
(cffi:define-foreign-type claw-pointer () ())
(cffi:define-parse-method claw-pointer (&optional (type :void))
(make-instance 'claw-pointer
:actual-type `(:pointer ,(cffi::canonicalize-foreign-type type))))
(defmethod cffi:expand-to-foreign (value (type claw-pointer))
(if value `(or ,value (cffi:null-pointer)) (cffi:null-pointer)))
(defmethod cffi:expand-from-foreign (value (type claw-pointer))
(declare (ignore type))
value)
;;;
;;; BITFIELD
;;;
(defmacro define-bitfield-from-enum (name enum)
`(cffi:defbitfield ,name
,@(loop for keyword in (cffi:foreign-enum-keyword-list enum)
collect (list keyword (cffi:foreign-enum-value enum keyword)))))
(defmacro define-bitfield-from-constants (name &body constants)
(let ((prefix-len (length (claw.util:common-prefix constants))))
`(cffi:defbitfield ,name
,@(loop for constant in constants
collect (let ((stringified (string constant)))
`(,(make-keyword (subseq stringified
prefix-len
(1- (length stringified))))
,(eval constant)))))))
;;;
;;; CLAW STRING
;;;
(cffi:define-foreign-type claw-string () ())
(cffi:define-parse-method claw-string ()
(make-instance 'claw-string :actual-type '(:pointer :char)))
;; TODO: Use stack allocation
(defmacro with-foreign-string* ((var string-or-ptr &rest args) &body body)
(with-gensyms (provided-p)
(once-only (string-or-ptr)
`(let* ((,provided-p (cffi:pointerp ,string-or-ptr))
(,var (or (and ,string-or-ptr
(if ,provided-p
,string-or-ptr
(cffi:foreign-string-alloc ,string-or-ptr ,@args)))
(cffi:null-pointer))))
(unwind-protect
(progn ,@body)
(unless (or ,provided-p (cffi:null-pointer-p ,var))
(cffi:foreign-string-free ,var)))))))
(defmethod cffi:expand-from-foreign (value (type claw-string))
(declare (ignore type))
value)
(defmethod cffi:expand-to-foreign-dyn (value var body (type claw-string))
(declare (ignore type))
`(with-foreign-string* (,var ,value)
,@body))
;;;
;;; CLAW ARRAY
;;;
(cffi:define-foreign-type claw-array ()
((array-type :initarg :array-type
:initform (error ":array-type missing")
:reader array-type-of)))
(cffi:define-parse-method claw-array (type &optional count)
(let ((array-type `(:array ,(cffi::canonicalize-foreign-type type)
,@(when count
`(,count)))))
(make-instance 'claw-array :array-type array-type
:actual-type array-type)))
(defmethod cffi:expand-from-foreign (value (type claw-array))
(declare (ignore type))
value)
(defmacro with-foreign-array* ((var array-or-ptr type) &body body)
(with-gensyms (provided-p)
(once-only (array-or-ptr)
`(let* ((,provided-p (cffi:pointerp ,array-or-ptr))
(,var (or (and ,array-or-ptr
(if ,provided-p
,array-or-ptr
(cffi:foreign-array-alloc ,array-or-ptr ,type)))
(cffi:null-pointer))))
(unwind-protect
(progn ,@body)
(unless (or ,provided-p (cffi:null-pointer-p ,var))
(cffi:foreign-array-free ,var)))))))
(defmethod cffi:expand-to-foreign-dyn (value var body (type claw-array))
`(with-foreign-array* (,var ,value ',(array-type-of type))
,@body))