Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can deserialization of polymorphic trait objects be added in Rust if at all?

I'm trying to solve the problem of serializing and deserializing Box<SomeTrait>. I know that in the case of a closed type hierarchy, the recommended way is to use an enum and there are no issues with their serialization, but in my case using enums is an inappropriate solution.

At first I tried to use Serde as it is the de-facto Rust serialization mechanism. Serde is capable of serializing Box<X> but not in the case when X is a trait. The Serialize trait can’t be implemented for trait objects because it has generic methods. This particular issue can be solved by using erased-serde so serialization of Box<SomeTrait> can work.

The main problem is deserialization. To deserialize polymorphic type you need to have some type marker in serialized data. This marker should be deserialized first and after that used to dynamically get the function that will return Box<SomeTrait>.

std::any::TypeId could be used as a marker type, but the main problem is how to dynamically get the deserialization function. I do not consider the option of registering a function for each polymorphic type that should be called manually during application initialization.

I know two possible ways to do it:

  1. Languages that have runtime reflection like C# can use it to get deserialization method.
  2. In C++, the cereal library uses magic of static objects to register deserializer in a static map at the library initialization time.

But neither of these options is available in Rust. How can deserialization of polymorphic objects be added in Rust if at all?

like image 909
Dmitry Gordon Avatar asked May 28 '17 19:05

Dmitry Gordon


People also ask

Does Deserialization create new object?

When you deserialize your object, the object will create a new entry in heap which will not have any references to any of the objects.

What is trait object in Rust?

A trait object is an opaque value of another type that implements a set of traits. The set of traits is made up of an object safe base trait plus any number of auto traits. Trait objects implement the base trait, its auto traits, and any supertraits of the base trait.

How does Serde work rust?

Serde is a framework for serializing and deserializing Rust data structures efficiently and generically. The Serde ecosystem consists of data structures that know how to serialize and deserialize themselves along with data formats that know how to serialize and deserialize other things.

What is Deserialization of object?

Deserialization is the process of reconstructing a data structure or object from a series of bytes or a string in order to instantiate the object for consumption. This is the reverse process of serialization, i.e., converting a data structure or object into a series of bytes for storage or transmission across devices.


1 Answers

This has been implemented by dtolnay.

The concept is quite clever ans is explained in the README:

How does it work?

We use the inventory crate to produce a registry of impls of your trait, which is built on the ctor crate to hook up initialization functions that insert into the registry. The first Box<dyn Trait> deserialization will perform the work of iterating the registry and building a map of tags to deserialization functions. Subsequent deserializations find the right deserialization function in that map. The erased-serde crate is also involved, to do this all in a way that does not break object safety.

To summarize, every implementation of the trait declared as [de]serializable is registered at compile-time, and this is resolved at runtime in case of [de]serialization of a trait object.

like image 86
Boiethios Avatar answered Oct 12 '22 01:10

Boiethios