<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>hyphenOs (Posts about De-serialization)</title><link>/</link><description></description><atom:link href="/categories/de-serialization.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2022 &lt;a href="mailto:mail@hyphenos.io"&gt;hyphenOs&lt;/a&gt; </copyright><lastBuildDate>Thu, 06 Oct 2022 03:43:26 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Rust `serde` Practical Guide</title><link>/blog/2022/rust-serde-practical-guide/</link><dc:creator>Abhijit Gadgil</dc:creator><description>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Often it is necessary to serialize or deserialize a user defined structure into some format on wire or on disk. For example, serializing a &lt;code&gt;struct&lt;/code&gt; to a JSON while working with REST APIs. Rust's &lt;code&gt;serde&lt;/code&gt; crate provides functionality to make this quite straight forward.  While using &lt;code&gt;serde&lt;/code&gt;, often, using the &lt;code&gt;derive&lt;/code&gt; macros &lt;code&gt;Serialize&lt;/code&gt; and &lt;code&gt;DeSerialize&lt;/code&gt; on a user defined structure is usually good enough. Things start to get little challenging, when one has to customize the serialize/deserialize behavior. While &lt;code&gt;serde&lt;/code&gt; provides a number of &lt;a href="https://serde.rs/attributes.html" target="_blank"&gt;attributes&lt;/a&gt; to make this easier, there are still some cases where one might be required to do little more than simply using those &lt;code&gt;attributes&lt;/code&gt;. To a first time user of &lt;code&gt;serde&lt;/code&gt;, it can be quite daunting especially when one reads example code that has  very similar looking &lt;code&gt;struct&lt;/code&gt;s or &lt;code&gt;trait&lt;/code&gt;s like &lt;code&gt;Serialize&lt;/code&gt;, &lt;code&gt;Serializer&lt;/code&gt; &lt;em&gt;etc&lt;/em&gt; and one is not quite sure what they should do to get started. In this blog we will primarily be looking at the cases where the user has to perform such customizations along with some other practical tips. One goal of this post is to also help reader in understanding the excellent &lt;a href="https://serde.rs/" target="_blank"&gt;&lt;code&gt;serde&lt;/code&gt; documentation&lt;/a&gt;, which at-least I have found challenging reading first few times.&lt;/p&gt;
&lt;h2&gt;Some Concepts&lt;/h2&gt;
&lt;p&gt;In &lt;code&gt;serde&lt;/code&gt; there are many 'traits'/'structs' that have similar looking names and that makes it a bit confusing. First, let's take a look at those -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There are two derive macros &lt;code&gt;Serialize&lt;/code&gt; and &lt;code&gt;DeSerialize&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;There are also traits with same name as &lt;code&gt;Serialize&lt;/code&gt; and &lt;code&gt;DeSerialize&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Also there are additional traits &lt;code&gt;Serializer&lt;/code&gt; and &lt;code&gt;DeSerializer&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We'll now see how they are related. In &lt;code&gt;serde&lt;/code&gt; there are primarily two concepts, &lt;a href="https://serde.rs/#serde" target="_blank"&gt;data structures and data formats&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A 'Data Structure' is typically any Rust user defined type. One will typically implement the trait &lt;code&gt;Serialize&lt;/code&gt; and/or &lt;code&gt;DeSerialize&lt;/code&gt; for these structures. If one simply wishes to use the sensible defaults that &lt;code&gt;serde&lt;/code&gt; provides, these traits can be implemented using the &lt;code&gt;derive&lt;/code&gt; macros above. For most common use cases this is suffice. There are cases, when one has to implement these 'traits' by hand. We will see some examples of that shortly.&lt;/p&gt;
&lt;p&gt;A 'Data Format' on the other hand is something that represents a structure on wire (or on disk) and it needs to know how individual fields in a &lt;code&gt;struct&lt;/code&gt; map to their on wire representation. In &lt;code&gt;serde&lt;/code&gt; an example of a Data Format is JSON. Typically, third party crates ( &lt;em&gt;eg&lt;/em&gt; &lt;a href="https://docs.rs/serde_json/latest/serde_json/" target="_blank"&gt;&lt;code&gt;serde_json&lt;/code&gt;&lt;/a&gt;) will implement sensible defaults for such serialization and de-serialization part for a given data format, this they will typically do by implementing a &lt;code&gt;Serializer&lt;/code&gt; and/or &lt;code&gt;Deserializer&lt;/code&gt; trait from the &lt;code&gt;serde&lt;/code&gt; crate on a &lt;code&gt;struct&lt;/code&gt; defined in that trait. For example, you will see a &lt;a href="https://github.com/serde-rs/json/blob/master/src/ser.rs#L14" target="_blank"&gt;&lt;code&gt;struct Serializer&lt;/code&gt;&lt;/a&gt; from the crate &lt;code&gt;serde-json&lt;/code&gt; that implements the &lt;a href="https://github.com/serde-rs/serde/blob/master/serde/src/ser/mod.rs#L331" target="_blank"&gt;&lt;code&gt;Serializer&lt;/code&gt;&lt;/a&gt; trait from the crate &lt;code&gt;serde&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also, note that once &lt;code&gt;Serialize&lt;/code&gt;/&lt;code&gt;DeSerialize&lt;/code&gt; trait is implemented on a data structure, it can be used with any data format. The 'Data Structure's and 'Data Format' interact through what is called as &lt;a href="https://serde.rs/data-model.html" target="_blank"&gt;&lt;code&gt;serde&lt;/code&gt; Data Model&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Simplest thing to keep in mind is -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you are just defining new 'struct's that have to be represented on wire using one of the supported 'Data Formats', simply using derive macros is enough.&lt;/li&gt;
&lt;li&gt;If you need to tweak the implementation of a serializer or a de-serializer, you may need to implement the &lt;code&gt;Serialize&lt;/code&gt;/&lt;code&gt;DeSerialize&lt;/code&gt; trait for your structure, but before that see if the attributes provided by serde are sufficient.&lt;/li&gt;
&lt;li&gt;If you are defining a new on wire or an on disk format, you will need to implement the &lt;code&gt;Serializer&lt;/code&gt;/&lt;code&gt;DeSerializer&lt;/code&gt; in your crate on one of the structures from your crate.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Custom Serialization/Deserialization&lt;/h2&gt;
&lt;p&gt;To help understand the concepts described in the previous section, let's look at some examples. &lt;code&gt;serde&lt;/code&gt;'s documentation is quite detailed for the built-in customization. Such a customization is possible over a container type (like a &lt;code&gt;struct&lt;/code&gt; or an &lt;code&gt;enum&lt;/code&gt;) or a variant of an &lt;code&gt;enum&lt;/code&gt; or individual field of a &lt;code&gt;struct&lt;/code&gt;. All available options are described &lt;a href="https://serde.rs/custom-serialization.html" target='"_blank'&gt;here&lt;/a&gt;). But it's possible to even go beyond what is provided by default. Some &lt;a href="https://serde.rs/examples.html" target='"_blank'&gt;examples&lt;/a&gt; are available that explain some more custom serialization.&lt;/p&gt;
&lt;p&gt;In the following discussions we will be talking a lot about &lt;code&gt;JSON&lt;/code&gt; data format, but the discussion remains just as much applicable for other data formats, JSON being very common, most of our examples focus on that. We will take a couple of more examples of 'custom' serialization.&lt;/p&gt;
&lt;h3&gt;Custom Serialization Example (integers as &lt;code&gt;hex&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Let's say we have a field in a &lt;code&gt;struct&lt;/code&gt; that is some integer type (say &lt;code&gt;u16&lt;/code&gt;), the default serialization behavior for integer types in &lt;code&gt;serde&lt;/code&gt; is the decimal representation of the integer. However if we would like to serialize this field to it's hex representation, there are a couple of ways this can be done. First, one can define a wrapping &lt;code&gt;struct&lt;/code&gt; type on the integer type and then implement &lt;code&gt;Serialize&lt;/code&gt; (or &lt;code&gt;Deserialize&lt;/code&gt;) for it that looks something like below (Please note we are not using a &lt;code&gt;#[derive(Serialize)]&lt;/code&gt; on the wrapping &lt;code&gt;struct&lt;/code&gt; below.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// No `[#derive(Serialize)] on this struct (or else it will use default decimal).&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;U16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;U16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;: &lt;span class="nc"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;::&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;::&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;: &lt;span class="nc"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="cp"&gt;#[derive(Serialize)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;: &lt;span class="nc"&gt;U16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;However, defining a wrapping &lt;code&gt;struct&lt;/code&gt; just for this alone is often too much of boilerplate code, instead we can use a &lt;code&gt;field&lt;/code&gt; &lt;code&gt;attribute&lt;/code&gt; on the &lt;code&gt;struct&lt;/code&gt; and simply derive &lt;code&gt;Serialize&lt;/code&gt; on rest of the &lt;code&gt;struct&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#[derive(Serialize)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;#[serde(serialize_with=&lt;/span&gt;&lt;span class="s"&gt;"number_as_hex"&lt;/span&gt;&lt;span class="cp"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;: &lt;span class="kt"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;number_as_hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;: &lt;span class="kt"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;: &lt;span class="nc"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;::&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;::&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;: &lt;span class="nc"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="fm"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0x02x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is much lesser boilerplate code achieving the same result. Note here, while we are implementing the &lt;code&gt;trait Serialize&lt;/code&gt; on the &lt;code&gt;struct&lt;/code&gt;, the &lt;code&gt;trait&lt;/code&gt; in the &lt;code&gt;where&lt;/code&gt; clause is a &lt;code&gt;Serializer&lt;/code&gt;. Also, the method &lt;code&gt;serialize_str&lt;/code&gt; is one of the &lt;code&gt;trait&lt;/code&gt; methods of the &lt;code&gt;Serializer&lt;/code&gt; trait. The &lt;code&gt;Serializer&lt;/code&gt; trait defines methods for all the &lt;code&gt;Rust&lt;/code&gt; primitive and other types like &lt;code&gt;struct&lt;/code&gt;, &lt;code&gt;enum&lt;/code&gt; &lt;em&gt;etc&lt;/em&gt;. This trait will typically be implemented by a crate that is implementing the &lt;code&gt;Data Format&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Custom Deserialization example (Default when JSON &lt;code&gt;null&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;In many APIs there might be some fields which are optional or if present null and in such cases, we may want to use the default value of the field type if it exists (&lt;em&gt;ie&lt;/em&gt; if the field type implements &lt;code&gt;Default&lt;/code&gt; trait). This can be done by again implementing a custom 'deserialization' function &lt;a href="https://stackoverflow.com/a/65705111/2845044" target='"_blank'&gt;as follows&lt;/a&gt;)&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#[derive(Deserialize)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="cp"&gt;#[serde(deserialize_with = &lt;/span&gt;&lt;span class="s"&gt;"deserialize_null_default"&lt;/span&gt;&lt;span class="cp"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;: &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;deserialize_null_default&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;'&lt;/span&gt;&lt;span class="na"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deserializer&lt;/span&gt;: &lt;span class="nc"&gt;D&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;::&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;: &lt;span class="nb"&gt;Default&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;'&lt;/span&gt;&lt;span class="na"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;: &lt;span class="nc"&gt;Deserializer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;'&lt;/span&gt;&lt;span class="na"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Option&lt;/span&gt;::&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unwrap_or_default&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note the &lt;code&gt;trait&lt;/code&gt; bounds for the types &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;D&lt;/code&gt;. &lt;code&gt;T&lt;/code&gt; in this case is the Data Structure (which implements &lt;code&gt;Deserialize&lt;/code&gt; trait, but in this example it also has to implement a &lt;code&gt;Default&lt;/code&gt; trait, since we need &lt;code&gt;default&lt;/code&gt; value), &lt;code&gt;D&lt;/code&gt; is the Data Format type that implements &lt;code&gt;Deserializer&lt;/code&gt; trait.&lt;/p&gt;
&lt;h3&gt;Custom Serialization of &lt;code&gt;Trait&lt;/code&gt; objects&lt;/h3&gt;
&lt;p&gt;Sometimes, it's possible that a structure that we are serializing has got a field that is a type implementing a trait &lt;em&gt;eg&lt;/em&gt; A vector of &lt;code&gt;Box&amp;lt;dyn CustomTrait&amp;gt;&lt;/code&gt;. It is possible to simply skip serializing that particular field or in some cases it may even be required to be able to &lt;code&gt;Serialize&lt;/code&gt; (and &lt;code&gt;Deserialize&lt;/code&gt;) that field. This is a bit involved and &lt;code&gt;erased_serde&lt;/code&gt; crate provides the functionality and performs the heavy lifting for it. Usually a couple of things are required to be done. The &lt;code&gt;trait&lt;/code&gt; whose &lt;code&gt;trait&lt;/code&gt; &lt;code&gt;objects&lt;/code&gt; are to be serialized will have to be Sub trait of &lt;code&gt;erased_serde::Serialize&lt;/code&gt;. This is explained in the documentation of &lt;a href="https://docs.serde.rs/erased_serde/index.html" target="_blank"&gt;&lt;code&gt;erased_serde&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We will look at a concrete example from one of the projects that we implemented where this feature of &lt;code&gt;serde&lt;/code&gt; was quite handy. We wanted to 'dump' contents of a Packet after parsing individual layers in the packet as a Json. Each of these layers implemented a &lt;code&gt;Layer&lt;/code&gt; trait and a packet was a collection of all such &lt;code&gt;Layer&lt;/code&gt; traits. An additional requirement was that each &lt;code&gt;Layer&lt;/code&gt; is to be identified by it's Layer name ( A function to obtain that was already a required method in the &lt;code&gt;Layer&lt;/code&gt; trait.). The following code shows the details of this implementation. We are mostly highlighting the parts that are important. A complete example can be seen in the &lt;a href="https://github.com/gabhijit/scalpel" target="_blank"&gt;repository&lt;/a&gt; in &lt;a href="https://github.com/gabhijit/scalpel/blob/master/src/packet.rs" target="_blank"&gt;&lt;code&gt;packet.rs&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/gabhijit/scalpel/blob/master/src/layer.rs" target="_blank"&gt;&lt;code&gt;layer.rs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;erased_serde&lt;/span&gt;::&lt;span class="n"&gt;serialize_trait_object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;trait&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Layer&lt;/span&gt;: &lt;span class="nc"&gt;Debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;erased_serde&lt;/span&gt;::&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="n"&gt;serialize_trait_object&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="cp"&gt;#[derive(Debug, Default, Serialize)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Packet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;'&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;#[serde(serialize_with = &lt;/span&gt;&lt;span class="s"&gt;"serialize_layers_as_struct"&lt;/span&gt;&lt;span class="cp"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Layer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;serialize_layers_as_struct&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Layer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;: &lt;span class="nc"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;::&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;::&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;: &lt;span class="nc"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize_struct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"layers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;short_name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In the example above even though the field &lt;code&gt;layers&lt;/code&gt; is a &lt;code&gt;Vec&lt;/code&gt;, since we want to be able to have the name of each layer available along with the it's serialized value, we are implementing a custom serialize function where the &lt;code&gt;Vec&lt;/code&gt; is actually serialized as a &lt;code&gt;struct&lt;/code&gt; using the &lt;code&gt;Serializer&lt;/code&gt; &lt;code&gt;trait&lt;/code&gt;'s &lt;code&gt;serialize_struct&lt;/code&gt; method and individual members of the &lt;code&gt;Vec&lt;/code&gt; are serialized as if they were &lt;code&gt;struct&lt;/code&gt; fields. This achieves our desired output.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post we looked at some of the ways Serialization and Deserialization of Rust types can be customized. Some of the important things to remember are -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Serialize&lt;/code&gt; is a trait that is to be implemented by the Data Structure to be serialized.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Serializer&lt;/code&gt; is a trait that is to be implemented by the &lt;code&gt;struct&lt;/code&gt; (or any type) implementing a Data Format.&lt;/li&gt;
&lt;li&gt;Typically a Data Format implementor will provide an API that will internally - generate a serializer &lt;code&gt;struct&lt;/code&gt; (implementing the &lt;code&gt;Serializer&lt;/code&gt; trait), pass the instance of the serializer &lt;code&gt;struct&lt;/code&gt; to the &lt;code&gt;serialize&lt;/code&gt; method of the value (defined in &lt;code&gt;Serialize&lt;/code&gt; trait) and returns the result (often a &lt;code&gt;String&lt;/code&gt; or &lt;code&gt;u8&lt;/code&gt; buffer.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Most examples in this blog post are taken from the &lt;a href="https://github.com/gabhijit/scalpel" target="_blank"&gt;&lt;code&gt;scalpel&lt;/code&gt;&lt;/a&gt; packet dissection crate.&lt;/p&gt;</description><category>De-serialization</category><category>Rust</category><category>Serde</category><category>Serialization</category><guid>/blog/2022/rust-serde-practical-guide/</guid><pubDate>Tue, 04 Oct 2022 12:32:00 GMT</pubDate></item></channel></rss>