Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Type registry

The original Scala desert library includes a type registry for cases where the concrete type is not known at compile time. A serialized value carries a compact type id, and the registry maps that id back to a codec during deserialization.

desert-rust does not currently expose an equivalent public type registry API. The placeholder remains in the book because this is an important concept in the Scala documentation and a likely future Rust feature.

What to use today

For closed sets of alternatives, use an enum:

use desert_rust::BinaryCodec;

#[derive(Debug, Clone, PartialEq, BinaryCodec)]
enum Message {
    Ping,
    Rename { id: u64, name: String },
    Delete { id: u64 },
}

This is the most idiomatic Rust option when all possible variants are known to the crate defining the protocol.

For open sets, define an application-level tag and implement the codec traits manually:

use desert_rust::{
    BinaryDeserializer, BinaryOutput, BinarySerializer, DeserializationContext,
    Error, Result, SerializationContext,
};

trait PluginMessage {}

struct TextMessage(String);
impl PluginMessage for TextMessage {}

enum AnyMessage {
    Text(TextMessage),
}

impl BinarySerializer for AnyMessage {
    fn serialize<Output: BinaryOutput>(
        &self,
        context: &mut SerializationContext<Output>,
    ) -> Result<()> {
        match self {
            AnyMessage::Text(TextMessage(text)) => {
                1u32.serialize(context)?;
                text.serialize(context)
            }
        }
    }
}

impl BinaryDeserializer for AnyMessage {
    fn deserialize(context: &mut DeserializationContext<'_>) -> Result<Self> {
        match u32::deserialize(context)? {
            1 => Ok(AnyMessage::Text(TextMessage(String::deserialize(context)?))),
            other => Err(Error::InvalidConstructorId {
                constructor_id: other,
                type_name: "AnyMessage".to_string(),
            }),
        }
    }
}

Keep ids stable once data has been written. If an id is retired, leave it reserved so newer variants do not take over old meanings.

Difference from Scala

In Scala, the type registry is part of the public library API and is used by integrations such as actor serializers. In Rust, framework integration is currently expected to happen at the byte boundary: serialize a statically known type, or define your own dynamic envelope type as shown above.