Skip to content

Instantly share code, notes, and snippets.

@frsyuki
Last active December 14, 2015 03:09
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frsyuki/5018906 to your computer and use it in GitHub Desktop.
Save frsyuki/5018906 to your computer and use it in GitHub Desktop.

msgpackの変更案について

概要:

  • 現行のRaw型をString型として読み替える。
  • Binary型を新設する。
  • 明らかなバイナリはデフォルトでBinary型(新設型)で保存

型システムの変更

  • Binary: バイト列
    • 「明らかにバイト列である」と言うヒントが付いたStringである
  • String: UTF-8でエンコードされた文字列、もしくはバイト列
    • 明らかにバイト列であると区別できる場合、それはString型で保存されるべきではない(SHOULD NOT)
    • それ以外、すなわちバイト列と文字列の区別が曖昧な場合も、すべてString型で保存する

Stringがバイナリデータを含むかもしれない(UTF-8として不正なバイト列を含み得る)とした理由は、区別が曖昧な環境において、すべてのバイト列(もしくはすべての文字列)にマーカーを付ける作業が非現実的であるから、という根拠に基づく。

ただし、Stringを受け取ったときに、UTF-8としてinvalidなバイトシーケンスを含むデータだった場合に、これを弾く実装を行っても良い(MAY)。この実装はオプションとして提供され、UTF-8としてinvalidなバイトシーケンスを含むString型オブジェクトを取り出せるようにする手段も提供することが強く推奨される(SHOULD)。

フォーマットの変更

0xa0-0xbf FixString (0bytes - 31bytes String type)  // changed

0xd5 binary 8 (0bytes - 255bytes Raw type)  // new
0xd6 binary 16 (256bytes - 65535bytes Raw type)  // new
0xd7 binary 32 (65536bytes - 4294967295bytes Raw type)  // new

0xd8 reserved

0xd9 string 8 (32bytes - 255bytes String type)  // new
0xda string 16 (256bytes - 65535bytes String type)  // changed from raw 16
0xdb string 32 (65536bytes - 4294967295bytes String type)  // changed from raw 32

区別が曖昧な環境における実装のガイドライン

  • シリアライザ:
    • 基本的に、文字列に見える物はすべてString型として保存する。invalidなエンコーディングが入っても良い
    • UTF-8のvalidationは行わない
    • 明示的に「これはバイト列だ」とヒントが付けられたオブジェクトを受け取った場合、それはBinary型として保存する(SHOULD)
  • デシリアライザ:
    • すべて文字列型やバイト列を格納する型にデコードする
    • String型でvalidationは行わない(SHOULD NOT)。invalidなバイトシーケンスを含むStringを受け取っても、そのまま格納する
    • String型でvalidationを行うオプションを実装をしてもよい(MAY)
    • Binary型を受け取った場合、何らかのフラグが立ったオブジェクトを返すのは良いアイディアだが、そうでなくても良いし、提供方法はオプションでも良い(MAY)
      • この挙動は、MessagePackを入力として、MessagePackを出力するような、中間処理を行うツールで、出力先でも型情報を維持しなければならないケースで必要になる
      • この機能が必要なケースは稀である
      • 実装の方法は、binary_as_classオプションがonであったら、Binary型を受け取った場合に、バイト列をフィールドとして所有するMessagePackBinaryクラスのインスタンスを返す方法ある。

区別が厳格な環境における実装のガイドライン

  • シリアライザ:

    • all_stringオプションがoff(デフォルト=off)
      • バイト列はBinary型として保存する
      • 文字列はString型として保存する
    • all_stringオプションがon
      • バイト列も文字列もRaw型として保存する
  • デシリアライザ:

    • all_rawオプションがon(デフォルト値、多言語間の互換性を高めるためにONであることが推奨される)
      • String型もBinary型もバイナリデータとして復元する
      • String型を受け取った場合、何かフラグが立ったバイト列型を返すのは良いアイディアだが、そうでなくても良い(MAY)
    • all_rawオプションがoff
      • Binary型を受け取ったら、バイト列を返す
      • String型を受け取ったら、文字列を返す
      • String型は、デシリアライズを行う段階で文字列のvalidationをしなくてもよい。してもよい。(←ここどうする?)
    • all_rawオプションの存在意義:
      • String型にUTF-8としてinvalidなバイトシーケンスが含まれていた場合に、アプリケーションがそれらをハンドリングできるようにする機能を提供するべきである(SHOULD)

バージョンアップについて

  1. マイナーバージョンアップで、新設される型をバイト列として返す実装をリリースする
  2. メジャーバージョンアップで、明らかなバイト列を新設Binary型でシリアライズする実装をリリースする(ソース互換性が失われることを明示)

区別が曖昧な言語において、String型でvalidationするオプションを実装するのは、マイナーバージョンでも良い。いずれにしても、デフォルトではvalidationしないことが推奨される(SHOULD NOT)

区別が厳格な環境において、メジャーバージョンアップでバイト列を新設Raw型でシリアライズする実装を行ったとき、all_stringオプションを同時に提供するべき。

用語

"区別が曖昧な環境" とは、文字列とバイト列を区別する型がそもそも無いか(PHP, C++, Erlang)、文字列を表すためにフラグ等の付加情報が使われるが、文字列なのに付加情報が付与されていないケースが一般的に存在する言語か(Perl, Ruby)、文字列をバイト列を格納クラスで扱うことが一般的に行われているか(?)、いずれかに該当する言語で書かれたプログラムを指す。

募集中のアイディア

「用語」で触れられている言語の種類を増やしたい。コメント求む。

この変更後のMessagePackの呼び方。

  • 案1:現行の仕様をMessagePack 0.9 と呼び、新しい仕様を MessagePack 1.0 と呼ぶ
  • 案2:現行の仕様をMessagePack 1.0 と呼び、新しい仕様を MessagePack 1.1 と呼ぶ
@mzp
Copy link

mzp commented Feb 23, 2013

  • OCamlでシリアライズ・デシリアライズする場合には、特におおきな問題はないと思います
  • OCaml(とCoq)は「文字列とバイト列を区別する型がそもそも無い」言語です
  • 「区別が厳格な環境」の言語の例も欲しいです
  • "MessagePackBinaryクラス"うんぬんの話は、たぶん特定言語のライブラリに依存した話だと思うので、その言語も明示してほしいです

@yfakariya
Copy link

twitter でも返信しましたが、ここに書いた方が共有しやすいのでこちらにも(msgpack-cli、つまり C#、VB あたりの場合):

  • この案について、互換性を保ちつつバージョンアップすることは可能です。
  • CLI は「区別が厳格な環境」であると解釈します(コンパイル後の中間言語(IL)レベルで char と byte(int8)を区別しているので)
  • 「all_rawオプションがoff」の場合の挙動について、CLI(Javaも)文字列は妥当な UTF-16 シーケンスでなければならないため、不正な UTF-8 シーケンスをvalidationせざるを得ません。その場合のデファクトがあった方がよいと思いますが、Java は例外にするのであればそれに揃えて例外にします(現状の実装は例外)
  • 「all_rawオプションの存在意義」の解釈として、「API はバイト列としてデシリアライズできるようにし、アプリケーションがハンドリングできるような選択肢を用意すべき」と解釈しました。

@myun2
Copy link

myun2 commented Feb 23, 2013

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment