この記事は、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関数で処理をしたものを返しています。これは何かというと、型側(つまり
Deserializetrait)での処理の柔軟性を高めるための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
https://crieit.net/posts/Serde-1-derive
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の理解を助けてくれました