1) GBoxed - это структуры, у которых нет идентичности 2) При передаче ссылок, ссылки всегда имеют ограниченное время действия 3) Структуры могут быть открытыми и закрытыми (opaque) Основной критерий: лисповский код не должен заботиться о владении структурами. Идентичности нет. Следствия: 1) Все GBoxed, созданные в лиспе, удаляются только лиспом (при необходимости делается копия) 2) Если foreign-функции возвращают GBoxed, то им владеет лисп (при необходимости делается копия) 3) В callback'и возможна передача по ссылке (в том случае, если не знаем, как присвоить значение исходной структуре); в этом случае после выхода из callback'а лисповский прокси помечается как невалидный и операции с ним приводят к исключению Для реализации надо, чтобы CFFI позволяло совершать действия по очистке в конце callback'а. Код: (defclass g-boxed-type () ((g-type-designator :initarg :g-type :initform ":G-TYPE must be specified" :accessor g-boxed-type-type))) ;;Some terminology: ;; * native structure - a C structure in foreign memory that ;; has the data and is expected to be passed/received by foreign functions ;; * proxy - a Lisp object (class or a structure) that is ;; equivalent to native structure (has the same data in it). Its lifetime is indefinite ;; and it is not affected by foreign code. ;; A proxy may (but not required to) contain pointer to its own copy of a ;; native structure. ;; * reference proxy - a proxy that is whose lifetime is equal to a duration ;; of a callback. Reference proxies can only be used during a callback that created them. ;(defgeneric create-proxy (type) ; "Creates a new proxy of a specified TYPE.") (defgeneric create-proxy-for-native (type native-ptr) (:documentation "Creates a proxy that is initialized by data contained in native structured pointed to by NATIVE-PTR. Created proxy should not be linked to NATIVE-PTR and should have indefinite lifetime (until garbage collector collects it). Specifically, if proxy need a pointer to native structure, it should make a copy of a structure. If proxy requires finalization, finalizers should be added.")) (defgeneric create-temporary-native (type proxy) (:documentation "Creates a native structure (or passes a pointer to copy contained in PROXY) that contains the same data that the PROXY contains and returns a pointer to it. This call is always paired by call to FREE-TEMPORARY-NATIVE and calls may be nested.")) (defgeneric free-temporary-native (type proxy native-ptr) (:documentation "Frees the native structure that was previously created by CREATE-TEMPORARY-NATIVE for the same PROXY. Also reads data from native structure pointer to by NATIVE-PTR and sets the PROXY to contain the same data. This call is always paired by call to CREATE-TEMPORARY-NATIVE and calls may be nested.")) (defgeneric create-reference-proxy (type native-ptr) (:documentation "Creates a reference proxy for a native structure pointed to by NATIVE-PTR. Reference proxy's lifetime is bound to duration of a callback. When the callback returns the reference proxy is declared invalid and operations on it are errors. This call is always paired by call to FREE-REFERENCE-PROXY and calls will not nest.")) (defgeneric free-reference-proxy (type proxy native-ptr) (:documentation "Frees a reference proxy PROXY previously created by call to CREATE-REFERENCE-PROXY. This call should ensure that all changes on PROXY are reflected in native structure pointed to by NATIVE-PTR. After a call to FREE-REFERENCE-PROXY, PROXY is declared invalid and using it is an error, operations on it should signal erros. This call is always paired by call to CREATE-REFERENCE-PROXY.")) (define-foreign-type g-boxed-foreign () ((g-type :initarg :g-type :initform (error ":G-TYPE must be specified") :reader g-boxed-foreign-g-type) (pass-type :initarg :pass-type :reader g-boxed-foreign-g-type :type (member :callback :normal) :initform :normal)) (:actual-type :pointer)) (defun g-boxed-foreign->boxed-type (type) nil) (defmethod translate-to-foreign (proxy (type g-boxed-foreign)) (let* ((boxed-type (g-boxed-foreign->boxed-type type)) (native-ptr (create-temporary-native boxed-type proxy))) (values native-ptr proxy))) (defmethod free-translated-object (native-ptr (type g-boxed-foreign) proxy) (let ((boxed-type (g-boxed-foreign->boxed-type type))) (free-temporary-native boxed-type proxy native-ptr))) (defmethod translate-from-foreign (native-ptr (type g-boxed-foreign)) (let ((boxed-type (g-boxed-foreign->boxed-type type))) (ecase ) (create-proxy-for-native boxed-type native-ptr)))