I’m still learning common lisp, but I made a macro that I think is pretty useful.
(defmacro build-struct (struct-name struct &rest rest)
(unless (find-symbol (string struct-name))
(error (format nil "No struct ~a found" struct-name)))
(labels ((make-struct-symbol (l)
(let* ((field (car l))
(value (cadr l))
(symbol (intern (format nil "~a.~a" (string struct-name) (string field)))
))
`(setf (,symbol ,struct) ,value))))
(let ((forms (mapcar #'make-struct-symbol rest)))
`(progn ,@forms))))
It’s very small and can turn this
(setf (wgpu-device-descriptor.next-in-chain desc) (cffi:null-pointer))
(setf (wgpu-device-descriptor.label desc) (cffi:lisp-string-to-foreign "device" label 6))
(setf (wgpu-device-descriptor.required-feature-count desc) 0)
(setf (wgpu-device-descriptor.required-limits desc) (cffi:null-pointer))
into this
(build-struct wgpu-device-descriptor desc
(next-in-chain (cffi:null-pointer))
(label (cffi:lisp-string-to-foreign "desc"))
(required-feature-count 0)
(required-limits (cffi:null-pointer)))
which is much more ergonomic imo
It was pointed out to me, by Vendethiel on the common lisp dicord, that I can actually write a kind of `with-c-struct` macro that would change the behavior of `setf` within its block to allow a syntax that’d more like
(with-c-struct structname
(setf field1 'foo
field2 'bar))
which would be even better!
So I guess that’s where I’m going next.