reliar-core 0.3.0

Pure envelope/message model shared by every Reliar crate — no storage or transport dependency.
Documentation
//! Transport mapping abstraction (ADR 0004). Implemented by transport crates such as
//! `reliar-transport-nats`, never by `reliar-core` itself.

use crate::SerializedEnvelope;

/// Converts a [`SerializedEnvelope`] to and from one transport's native message type `M`.
///
/// No implementation ships from `reliar-core` — a mapper's transport headers are a
/// **projection** of [`Metadata`](crate::Metadata), not a second source of truth (ADR 0004).
/// The reserved `reliar-*` header names a mapper writes are a public contract that every
/// transport crate follows so headers mean the same thing everywhere.
///
/// ```
/// use reliar_core::{EnvelopeMapper, SerializedEnvelope};
///
/// /// A toy in-memory transport message: just the raw body, no headers.
/// struct RawMessage(bytes::Bytes);
///
/// struct RawMapper;
///
/// #[derive(Debug)]
/// struct RawMapError;
/// impl core::fmt::Display for RawMapError {
///     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
///         f.write_str("cannot decode a bare payload back into an envelope")
///     }
/// }
/// impl std::error::Error for RawMapError {}
///
/// impl EnvelopeMapper<RawMessage> for RawMapper {
///     type Error = RawMapError;
///
///     fn encode(&self, envelope: &SerializedEnvelope) -> Result<RawMessage, Self::Error> {
///         Ok(RawMessage(envelope.body.clone()))
///     }
///
///     fn decode(&self, _message: RawMessage) -> Result<SerializedEnvelope, Self::Error> {
///         // A real mapper reads the envelope's metadata back from transport headers; this toy
///         // one has none to read, so decoding is always an error.
///         Err(RawMapError)
///     }
/// }
/// ```
pub trait EnvelopeMapper<M> {
    /// The mapper's own error type.
    type Error: std::error::Error + Send + Sync + 'static;

    /// Encodes a canonical envelope into the transport's native message type.
    ///
    /// # Errors
    ///
    /// Returns `Self::Error` if the transport's native message type cannot represent the
    /// envelope (e.g. a field it cannot carry).
    ///
    /// ```
    /// use reliar_core::{Envelope, EnvelopeMapper, Message};
    /// # struct RawMessage(bytes::Bytes);
    /// # struct RawMapper;
    /// # #[derive(Debug)]
    /// # struct RawMapError;
    /// # impl core::fmt::Display for RawMapError {
    /// #     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("nope") }
    /// # }
    /// # impl std::error::Error for RawMapError {}
    /// # impl EnvelopeMapper<RawMessage> for RawMapper {
    /// #     type Error = RawMapError;
    /// #     fn encode(&self, envelope: &reliar_core::SerializedEnvelope) -> Result<RawMessage, Self::Error> {
    /// #         Ok(RawMessage(envelope.body.clone()))
    /// #     }
    /// #     fn decode(&self, _message: RawMessage) -> Result<reliar_core::SerializedEnvelope, Self::Error> {
    /// #         Err(RawMapError)
    /// #     }
    /// # }
    ///
    /// #[derive(serde::Serialize, serde::Deserialize)]
    /// struct Ping;
    /// impl Message for Ping {
    ///     const TYPE: &'static str = "ping";
    ///     const VERSION: u16 = 1;
    /// }
    ///
    /// let envelope = Envelope::builder(Ping)
    ///     .build()
    ///     .map_body(|_| bytes::Bytes::from_static(b"{}"));
    ///
    /// let wire = RawMapper.encode(&envelope)?;
    /// assert_eq!(wire.0.as_ref(), b"{}");
    /// # Ok::<(), RawMapError>(())
    /// ```
    fn encode(&self, envelope: &SerializedEnvelope) -> Result<M, Self::Error>;

    /// Decodes a transport message back into a canonical envelope.
    ///
    /// # Errors
    ///
    /// Returns `Self::Error` if the transport message cannot be decoded into a canonical
    /// envelope (a missing required framework header, or a malformed one).
    ///
    /// ```
    /// use reliar_core::EnvelopeMapper;
    /// # struct RawMessage(bytes::Bytes);
    /// # struct RawMapper;
    /// # #[derive(Debug)]
    /// # struct RawMapError;
    /// # impl core::fmt::Display for RawMapError {
    /// #     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("nope") }
    /// # }
    /// # impl std::error::Error for RawMapError {}
    /// # impl EnvelopeMapper<RawMessage> for RawMapper {
    /// #     type Error = RawMapError;
    /// #     fn encode(&self, envelope: &reliar_core::SerializedEnvelope) -> Result<RawMessage, Self::Error> {
    /// #         Ok(RawMessage(envelope.body.clone()))
    /// #     }
    /// #     fn decode(&self, _message: RawMessage) -> Result<reliar_core::SerializedEnvelope, Self::Error> {
    /// #         Err(RawMapError)
    /// #     }
    /// # }
    ///
    /// // This toy mapper has no headers to read back, so decoding is always an error.
    /// assert!(RawMapper.decode(RawMessage(bytes::Bytes::new())).is_err());
    /// ```
    fn decode(&self, message: M) -> Result<SerializedEnvelope, Self::Error>;
}