Previous: バイトのunpackとpackを行う関数, Up: バイト配列のpackとunpack [Contents][Index]
Bindatタイプ式は、これまでに説明したタイプに限定されません。Bindatタイプ式をリターンする、任意のLispフォームも可能です。たとえば以下のタイプは24ビットカラー、またはバイトのベクターのいずれかを含むことが可能なデータを記述します:
(bindat-type (len u8) (payload . (if (zerop len) (uint 24) (vec (1- len)))))
さらに複合タイプは通常は連想リストにunpack(または逆にpack)されませんが、以下のスペシャルキーワード引数を使用してこれを変更することができます:
:unpack-val expフィールドのリストがこのキーワードで終わる場合には、unpack時リターンされる値は標準のalistではなくexpの値となる。expは名前によって前のフィールドすべてを参照できる。
:pack-val expこのキーワード引数がフィールドのタイプの後に続く場合には、このフィールドにはalistから抽出するかわりにexpがリターンした値がpackされる。
:pack-var nameこのキーワード引数がフィールドのリストの前に前置されている場合には、後続するすべての:pack-val引数がnameという名前の引数を介して、この複合タイプにpackされた全体値を参照できる。
たとえば以下のように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-defmacroでBindatタイプ式を使用することによって、Bindatタイプフォームを新たに定義できます:
argsを受け取るnameという名前のBindatタイプ式を新たに定義する。これの挙動はdefmacroに準ずるが、重要な違いは新たなフォームがBindatタイプ式でのみ使用できることである。