41.20.3 Спецификации продвинутой компоновки данных

Выражения типа Bindat не ограничиваются типами, описанными ранее. Они также могут быть произвольными формами Lisp, возвращающими выражения типа Bindat. Например, нижеописанный тип описывает данные, которые могут содержать либо 24-битный код ошибки, либо вектор байтов:

(bindat-type
  (len      u8)
  (payload  . (if (zerop len) (uint 24) (vec (1- len)))))

Кроме того, хотя составные типы обычно распаковываются в (и упаковываются из) ассоциативных списков, это поведение можно изменить с помощью следующих специальных аргументов ключевых слов:

:unpack-val выр

Если список полей заканчивается этим аргументом ключевого слова, то при распаковке возвращается значение выр вместо стандартного ассоциативного списка. выр может ссылаться на все предыдущие поля по их именам.

:pack-val выр

Если за типом поля следует этот аргумент ключевого слова, то значение, упаковываемое в это поле, возвращается выр вместо извлечения из ассоциативного списка.

:pack-var имя

Если списку полей предшествует этот аргумент ключевого слова, то все последующие аргументы :pack-val могут ссылаться на общее значение, упаковываемое в этот составной тип, через переменную с именем имя.

Например, можно описать 16-битное целое число со знаком следующим образом:

(defconst sint16-bindat-spec
  (let* ((max (ash 1 15))
         (wrap (+ max max)))
    (bindat-type :pack-var v
                 (n uint 16 :pack-val (if (< v 0) (+ v wrap) v))
                 :unpack-val (if (>= n max) (- n wrap) n))))

После чего его поведение будет следующим:

(bindat-pack sint16-bindat-spec -8)
     ⇒ "\377\370"

(bindat-unpack sint16-bindat-spec "\300\100")
     ⇒ -16320

Наконец, вы можете определять новые формы типа Bindat для использования в выражениях типа Bindat с помощью bindat-defmacro:

Макрос: bindat-defmacro имя арги &rest тело

Определяет новое выражение типа Bindat с именем имя, принимающее аргументы арги. Его поведение соответствует поведению defmacro, с важным отличием: новые формы могут использоваться только внутри выражений типа Bindat.