Previous: , Up: バイト配列のpackとunpack   [Contents][Index]


40.20.3 高度なデータレイアウト仕様

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タイプフォームを新たに定義できます:

Macro: bindat-defmacro name args &rest body

argsを受け取るnameという名前のBindatタイプ式を新たに定義する。これの挙動はdefmacroに準ずるが、重要な違いは新たなフォームがBindatタイプ式でのみ使用できることである。