From: espen Date: Tue, 25 Apr 2006 20:37:49 +0000 (+0000) Subject: Initial checkin, code moved from glib/genums.lisp X-Git-Url: https://git.distorted.org.uk/~mdw/clg/commitdiff_plain/e6813115567e9df9ec8ccb0714c8aa6fa0f65e6c Initial checkin, code moved from glib/genums.lisp --- diff --git a/gffi/enums.lisp b/gffi/enums.lisp new file mode 100644 index 0000000..d97ef70 --- /dev/null +++ b/gffi/enums.lisp @@ -0,0 +1,292 @@ +;; Common Lisp bindings for GTK+ v2.x +;; Copyright 2000-2006 Espen S. Johnsen +;; +;; Permission is hereby granted, free of charge, to any person obtaining +;; a copy of this software and associated documentation files (the +;; "Software"), to deal in the Software without restriction, including +;; without limitation the rights to use, copy, modify, merge, publish, +;; distribute, sublicense, and/or sell copies of the Software, and to +;; permit persons to whom the Software is furnished to do so, subject to +;; the following conditions: +;; +;; The above copyright notice and this permission notice shall be +;; included in all copies or substantial portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +;; $Id: enums.lisp,v 1.1 2006-04-25 20:37:49 espen Exp $ + +(in-package "GFFI") + +;;;; Generic enum type + +(defun %map-enum (mappings op) + (delete-duplicates + (loop + as value = 0 then (1+ value) + for mapping in mappings + collect (let ((symbol (if (atom mapping) mapping (first mapping)))) + (unless (atom mapping) + (setq value (second mapping))) + (ecase op + (:symbol-int `(,symbol ,value)) + (:int-symbol `(,value ,symbol)) + (:int-quoted-symbol `(,value ',symbol))))) + :key #'first :from-end t)) + +(defun %map-symbols (mappings) + (mapcar #'(lambda (mapping) + (first (mklist mapping))) + mappings)) + +(deftype enum (&rest args) + `(member ,@(%map-symbols args))) + +(define-type-method alien-type ((type enum)) + (declare (ignore type)) + (alien-type 'signed)) + +(define-type-method size-of ((type enum) &key (inlined t)) + (assert-inlined type inlined) + (size-of 'signed)) + +(define-type-method to-alien-form ((type enum) form &optional copy-p) + (declare (ignore copy-p)) + `(case ,form + ,@(%map-enum (rest (type-expand-to 'enum type)) :symbol-int) + (t (error 'type-error :datum ,form :expected-type ',type)))) + +(define-type-method from-alien-form ((type enum) form &key ref) + (declare (ignore ref)) + `(case ,form + ,@(%map-enum (rest (type-expand-to 'enum type)) :int-quoted-symbol))) + +(define-type-method to-alien-function ((type enum) &optional copy-p) + (declare (ignore copy-p)) + (let ((mappings (%map-enum (rest (type-expand-to 'enum type)) :symbol-int))) + #'(lambda (enum) + (or + (second (assoc enum mappings)) + (error 'type-error :datum enum :expected-type type))))) + +(define-type-method from-alien-function ((type enum) &key ref) + (declare (ignore ref)) + (let ((mappings (%map-enum (rest (type-expand-to 'enum type)) :int-symbol))) + #'(lambda (int) + (second (assoc int mappings))))) + +(define-type-method writer-function ((type enum) &key temp (inlined t)) + (declare (ignore temp)) + (assert-inlined type inlined) + (let ((writer (writer-function 'signed)) + (function (to-alien-function (type-expand-to 'enum type)))) + #'(lambda (enum location &optional (offset 0)) + (funcall writer (funcall function enum) location offset)))) + +(define-type-method reader-function ((type enum) &key ref (inlined t)) + (declare (ignore ref)) + (assert-inlined type inlined) + (let ((reader (reader-function 'signed)) + (function (from-alien-function (type-expand-to 'enum type)))) + #'(lambda (location &optional (offset 0)) + (funcall function (funcall reader location offset))))) + +(defun enum-int (enum type) + (funcall (to-alien-function type) enum)) + +(defun int-enum (int type) + (funcall (from-alien-function type) int)) + +(defun enum-mapping (type) + (rest (type-expand-to 'enum type))) + + +;;;; Named enum types + +(defmacro define-enum-type (name &rest args) + (let ((enum-int (intern (format nil "~A-TO-INT" name))) + (int-enum (intern (format nil "INT-TO-~A" name)))) + `(progn + (deftype ,name () '(enum ,@args)) + (defun ,enum-int (enum) + (case enum + ,@(%map-enum args :symbol-int) + (t (error 'type-error :datum enum :expected-type ',name)))) + (defun ,int-enum (value) + (case value + ,@(%map-enum args :int-quoted-symbol))) + (eval-when (:compile-toplevel :load-toplevel :execute) + (define-type-method to-alien-form ((type ,name) form &optional copy-p) + (declare (ignore type copy-p)) + (list ',enum-int form)) + (define-type-method from-alien-form ((type ,name) form &key ref) + (declare (ignore type ref)) + (list ',int-enum form)) + (define-type-method to-alien-function ((type ,name) &optional copy-p) + (declare (ignore type copy-p)) + #',enum-int) + (define-type-method from-alien-function ((type ,name) &key ref) + (declare (ignore type ref)) + #',int-enum) + (define-type-method writer-function ((type ,name) &key temp (inlined t)) + (declare (ignore temp)) + (assert-inlined type inlined) + (let ((writer (writer-function 'signed))) + #'(lambda (enum location &optional (offset 0)) + (funcall writer (,enum-int enum) location offset)))) + (define-type-method reader-function ((type ,name) &key ref (inlined t)) + (declare (ignore ref)) + (assert-inlined type inlined) + (let ((reader (reader-function 'signed))) + #'(lambda (location &optional (offset 0)) + (,int-enum (funcall reader location offset))))))))) + + +;;;; Generic flags type + +(defun %map-flags (mappings op) + (delete-duplicates + (loop + as value = 1 then (ash value 1) + for mapping in mappings + collect (let ((symbol (if (atom mapping) mapping (first mapping)))) + (unless (atom mapping) + (setq value (second mapping))) + (case op + (:symbol-int `(,symbol ,value)) + (:int-symbol `(,value ,symbol))))) + :key #'first :from-end t)) + +(deftype flags (&rest args) + `(or (member ,@(%map-symbols args)) list)) + +(define-type-method alien-type ((type flags)) + (declare (ignore type)) + (alien-type 'unsigned)) + +(define-type-method size-of ((type flags) &key (inlined t)) + (assert-inlined type inlined) + (size-of 'unsigned)) + +(define-type-method to-alien-form ((type flags) flags &optional copy-p) + (declare (ignore copy-p)) + `(reduce #'logior (mklist ,flags) + :key #'(lambda (flag) + (case flag + ,@(%map-flags (rest (type-expand-to 'flags type)) :symbol-int) + (t (error 'type-error :datum ,flags :expected-type ',type)))))) + +(define-type-method from-alien-form ((type flags) value &key ref) + (declare (ignore ref)) + `(loop + for (int symbol) in ',(%map-flags (rest (type-expand-to 'flags type)) :int-symbol) + when (= (logand ,value int) int) + collect symbol)) + +(define-type-method to-alien-function ((type flags) &optional copy-p) + (declare (ignore copy-p)) + (let ((mappings (%map-flags (rest (type-expand-to 'flags type)) :symbol-int))) + #'(lambda (flags) + (reduce #'logior (mklist flags) + :key #'(lambda (flag) + (or + (second (assoc flag mappings)) + (error 'type-error :datum flags :expected-type type))))))) + +(define-type-method from-alien-function ((type flags) &key ref) + (declare (ignore ref)) + (let ((mappings (%map-flags (rest (type-expand-to 'flags type)) :int-symbol))) + #'(lambda (value) + (loop + for (int symbol) in mappings + when (= (logand value int) int) + collect symbol)))) + +(define-type-method writer-function ((type flags) &key temp (inlined t)) + (declare (ignore temp)) + (assert-inlined type inlined) + (let ((writer (writer-function 'unsigned)) + (function (to-alien-function (type-expand-to 'flags type)))) + #'(lambda (flags location &optional (offset 0)) + (funcall writer (funcall function flags) location offset)))) + +(define-type-method reader-function ((type flags) &key ref (inlined t)) + (declare (ignore ref)) + (assert-inlined type inlined) + (let ((reader (reader-function 'unsigned)) + (function (from-alien-function (type-expand-to 'flags type)))) + #'(lambda (location &optional (offset 0)) + (funcall function (funcall reader location offset))))) + + +;;;; Named flags types + +(defmacro define-flags-type (name &rest args) + (let ((flags-int (intern (format nil "~A-TO-INT" name))) + (int-flags (intern (format nil "INT-TO-~A" name))) + (satisfies (intern (format nil "~A-P" name)))) + `(progn + (deftype ,name () '(satisfies ,satisfies)) + (defun ,satisfies (object) + (flet ((valid-p (ob) + (find ob ',(%map-symbols args)))) + (typecase object + (symbol (valid-p object)) + (list (every #'valid-p object))))) + (defun ,flags-int (flags) + (reduce #'logior (mklist flags) + :key #'(lambda (flag) + (case flag + ,@(%map-flags args :symbol-int) + (t (error 'type-error :datum flags :expected-type ',name)))))) + (defun ,int-flags (value) + (loop + for (int symbol) in ',(%map-flags args :int-symbol) + when(= (logand value int) int) + collect symbol)) + (eval-when (:compile-toplevel :load-toplevel :execute) + (define-type-method alien-type ((type ,name)) + (declare (ignore type)) + (alien-type 'flags)) + (define-type-method size-of ((type ,name) &key (inlined t)) + (assert-inlined type inlined) + (size-of 'flags)) + (define-type-method to-alien-form ((type ,name) form &optional copy-p) + (declare (ignore type copy-p)) + (list ',flags-int form)) + (define-type-method from-alien-form ((type ,name) form &key ref) + (declare (ignore type ref)) + (list ',int-flags form)) + (define-type-method to-alien-function ((type ,name) &optional copy-p) + (declare (ignore type copy-p)) + #',flags-int) + (define-type-method from-alien-function ((type ,name) &key ref) + (declare (ignore type ref)) + #',int-flags) + (define-type-method writer-function ((type ,name) &key temp (inlined t)) + (declare (ignore temp)) + (assert-inlined type inlined) + (let ((writer (writer-function 'signed))) + #'(lambda (flags location &optional (offset 0)) + (funcall writer (,flags-int flags) location offset)))) + (define-type-method reader-function ((type ,name) &key ref (inlined t)) + (declare (ignore ref)) + (assert-inlined type inlined) + (let ((reader (reader-function 'signed))) + #'(lambda (location &optional (offset 0)) + (,int-flags (funcall reader location offset))))))))) + + +(defexport define-enum-type (name &rest args) + (declare (ignore args)) + name) + +(defexport define-flags-type (name &rest args) + (declare (ignore args)) + name)