titan-api-codec 1.2.9

Helpers for encoding and decoding Titan API messages
Documentation
//! Common traits and implementations for decoding of messages from binary representations.

// TODO: Look into how to allow for no-copy deserialization to work with tranforms.
// Would likely need for decode to return some intermediate object that contains both the
// deserialized value as well as a Bytes with the underlying data, whether that be the original
// data or the transformed data.

use bytes::Bytes;
use serde::de::DeserializeOwned;
use thiserror::Error;

use crate::transform::BinaryTransform;

/// Possible errors that can occur while decoding messages.
#[derive(Error, Debug)]
pub enum DecodeError {
    /// Serialization to the data format failed.
    #[error("Failed to deserialize message from binary data")]
    DeserializationFailed(#[from] Box<dyn std::error::Error + Send + Sync>),
    /// Transformation of the serialized data failed (ex. compression).
    #[error("Failed to apply transform to serialized data")]
    TransformFailed(#[from] std::io::Error),
}

/// A decoder that can transform binary data into a serde-deserializable object.
pub trait Decoder {
    /// Attempt to decode the given binary data.
    fn decode<T>(&self, data: Bytes) -> Result<T, DecodeError>
    where
        T: DeserializeOwned;

    /// Attempt to decode the given binary data, possibly mutating the state of the decoder.
    fn decode_mut<T>(&mut self, data: Bytes) -> Result<T, DecodeError>
    where
        T: DeserializeOwned,
    {
        self.decode(data)
    }

    /// Wraps this decoder, first applying `transformer` to any data before passing it to the
    /// decoder.
    fn transformed<BT>(self, transformer: BT) -> TransformedDecoder<Self, BT>
    where
        Self: Sized,
        BT: BinaryTransform,
    {
        TransformedDecoder::new(self, transformer)
    }
}

/// A decoder that wraps another [`Decoder`], first applying a [`BinaryTransform`] to the data.
pub struct TransformedDecoder<D: Decoder, BT: BinaryTransform> {
    decoder: D,
    transformer: BT,
}

impl<D: Decoder, BT: BinaryTransform> TransformedDecoder<D, BT> {
    // Wraps `decoder`, applying `transformer` to any data before passing the result for decoding.
    fn new(decoder: D, transformer: BT) -> Self {
        Self {
            decoder,
            transformer,
        }
    }
}

impl<D: Decoder, BT: BinaryTransform> Decoder for TransformedDecoder<D, BT> {
    fn decode<T>(&self, data: Bytes) -> Result<T, DecodeError>
    where
        T: DeserializeOwned,
    {
        self.decoder.decode(
            self.transformer
                .transform(data)
                .map_err(DecodeError::TransformFailed)?,
        )
    }

    fn decode_mut<T>(&mut self, data: Bytes) -> Result<T, DecodeError>
    where
        T: DeserializeOwned,
    {
        self.decoder.decode_mut(
            self.transformer
                .transform_mut(data)
                .map_err(DecodeError::TransformFailed)?,
        )
    }
}