この記事は、Zennにも投稿しています。
概要
Serdeで任意の形式のファイルなどをデシリアライズする際にはDeserializerを書く必要があります。この記事では基本的なDeserializerの書き方を解説します。
正直自分もあまり理解していない部分が多々あるのですが世に出ている情報が少ないので書くことにしました。
正直自分もあまり理解していない部分が多々あるのですが世に出ている情報が少ないので書くことにしました。
コードの概観
serdeのDeserializerを実装するというのはつまり、「
Deserializer
トレイトを実装した構造体を用意する」ということです。ある文字列をデシリアライズするための関数from_str
の概略コードは以下のようになります(あくまでイメージです)。ここで、
MyDeserializer
がデシリアライザ本体、T: Deserialize
は#[derive(Deserialize)]
などによりserde::de::Deserialize
が実装された型のことですね。デシリアライズの基本を理解する
この記事では、超基本的なデシリアライザを実装して流れを理解していくことを目指します。
今回実装するのは、「
"true"
か"false"
の文字列を受けとり、それをbool
型にデシリアライズするだけ」のデシリアライザです。プロジェクトの作成
次のコマンドで、プロジェクトを作成し必要になるクレートを追加します。
Errorの作成
まずはDeserializerのエラー型を作ります。これはDeserializerの関連型として必須で、
Deserializerを実装するのはライブラリであることが多いと思うので今回はthiserrorを使います。
serde::de::Error
を実装している必要があります。Deserializerを実装するのはライブラリであることが多いと思うので今回はthiserrorを使います。
Deserializerの実装
BoolDeserializer
という構造体にDeserializer
を適切に実装したものが以下になります。実行してみる
なにはともあれ、実行してみましょう。以下のようなコードとテストを追加します。
cargo test
で実行すると以下のような出力が得られるはずです。"true"
という文字列が正常にtrue
にデシリアライズされ、さらに"true"
という文字列であっても型がStringであればUnsupportedのエラーが発生していることがわかります。解説
Deserialize
を実装するには上で書いたエラー型、そしてdeserialize_
で始まる、一連の型をデシリアライズするためのメソッドが必要です。deserialize_
メソッドは対応する型がserdeに判別されて呼ばれます。全てのメソッドは以下のページで確認できます。Deserializer in serde - Rust
docs.rs
ただし、
今回は
forward_to_deserialize_any
マクロを使用することで、それらをdeserialize_any
メソッドに飛ばすことが可能です。今回は
bool
のみをデシリアイズするDeserializerであるため、bool
以外の全ての型をdeserialize_any
に飛ばしています。そして実際にdeserialize_any
で行われる処理はサポートされていないというエラーメッセージを返すことだけです。そして重要なのがbool型をデシリアライズする
これは何かというと、型側(つまり
deserialize_bool
メソッドです。今回は受け取った文字列が"true"
であればtrue
、"false"
であればfalse
を返す処理にしたいわけですが、上の例では単に値を返すのではなく、何やら引数として受け取ったvisitor: Visitor
のvisit_bool
関数で処理をしたものを返しています。これは何かというと、型側(つまり
Deserialize
trait)での処理の柔軟性を高めるためのserde
の機構だと思います。次にこのVisitorについて解説します。Visitorについて
このコードを見れば
Deserialize::deserialize -> Deserializer::deserialize_bool -> Visitor::visit_bool
の順で処理されていることがよりわかりやすいと思います。また、先程のコードで実際に
deserialize_bool
に渡されていたVisitor
はBoolVisitor
だったということがわかります。そして、BoolVisitor
にはexpecting
とvisit_bool
の二つのメソッドが実装されています。詳しくはdocs.rsに解説がありますが、expecting
はエラーメッセージに使われ、visit_bool
はDeserializerで処理されたbool値を受けとり、Self::Value
型を返しています。その他のメソッドは実装されていませんが、デフォルト実装でエラーが返るようになっています。bool
型の実装を見ても当然bool
型をそのまま返しているだけなので「これって何の意味があるんだろう」と感じるかもしれません。しかし、例えばbool
型からNewType構造体にデシリアライズされてほしいような型があるときにVisitorが役に立ちそうです。先程のテストコードに以下を追加してみます。ここで重要なのは、
Deserializer
には一切手を加えていないということです。つまり、Deserializer
はserdeによって決められた基本的なインターフェースさえ実装すればDeserialize
を実装するあらゆる型をデシリアライズできるのです。最後に
この記事では、簡単なDeserializerを実装してserdeでのデシリアライズの流れを追ってみました。参考になれば幸いです。
また、最初にも書きましたが、自分自身も(特にVisitor周りなど)これで理解が正しいのか曖昧な部分があります。間違いなどがありましたらコメントなどで教えていただけると嬉しいです
参考にさせていただいたサイト
Implementing a Deserializer · Serde
serde.rs
Deserializerの実装方法についての公式ドキュメント
serdeマニュアル -Deserializerについて- | 株式会社RICOS
serdeマニュアル -Deserializerについて-のページです。
www.ricos.co.jp
crieit.net | 525: SSL handshake failed
crieit.net
Why are there 2 types for deserializing in serde?
To expand a bit on @RustyYato's notes about the serde data model: serde has sort of a two-phase process to deserialization. One part deals with generic data formats, and the other deals with specific data structures. The job of the Deserializer is to deal with the "general-purpose" data format. It parses input and converts it into the basic serde data model. It's kind of like if you took all of your inputs in whatever format (TOML, CBOR, etc.) and converted them all to JSON so that the rest of ...
users.rust-lang.org
Visitorの理解を助けてくれました