//! Codec traits for encoding and decoding values. //! //! Codecs are marker types (e.g., [`Cbor`](cbor::Cbor), [`Json`](json::Json)) //! that implement [`Encode`] and [`Decode`] for the value types they support. //! //! The marker types are always available regardless of feature flags. //! Enable the corresponding feature (`minicbor`, `serde_json`) to get //! [`Encode`]/[`Decode`] implementations backed by a concrete serialization //! library. use alloc::vec::Vec; pub mod cbor; pub mod json; /// A codec that can encode values of type `T` to bytes. pub trait Encode { /// The error type returned when encoding fails. type Error: core::fmt::Debug; /// Encode `value` into a byte vector. /// /// # Errors /// /// Returns an error if the value cannot be serialized to bytes. fn encode(value: &T) -> Result, Self::Error>; } /// A codec that can decode bytes into values of type `T`. pub trait Decode { /// The error type returned when decoding fails. type Error; /// Decode a value of type `T` from `bytes`. /// /// # Errors /// /// Returns an error if the bytes cannot be deserialized into `T`. fn decode(bytes: &[u8]) -> Result; } /// Marker trait for codecs that produce deterministic (canonical) encodings. /// /// A canonical codec guarantees that the same value always encodes to /// identical bytes, which is essential for content-addressed hashing. pub trait Canonical {} /// Identity codec that passes bytes through unchanged. /// /// Useful for testing or when values are already serialized. /// /// # Example /// /// ``` /// # #[cfg(feature = "sha2")] /// # { /// use evidence::digest::{Digest, sha2::Sha256}; /// use evidence::codec::Identity; /// /// let data = b"hello world"; /// let digest: Digest<[u8; 11], Sha256, Identity> = Digest::hash(data); /// assert_eq!(digest.as_bytes().len(), 32); /// # } /// ``` #[derive(Debug, Clone, Copy)] pub enum Identity {} impl> Encode for Identity { type Error = core::convert::Infallible; fn encode(value: &T) -> Result, Self::Error> { Ok(value.as_ref().to_vec()) } } /// Error returned when decoding with Identity codec fails due to length mismatch. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct IdentityDecodeError { /// The number of bytes expected. pub expected: usize, /// The number of bytes actually received. pub actual: usize, } impl core::fmt::Display for IdentityDecodeError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "length mismatch: expected {} bytes, got {}", self.expected, self.actual ) } } impl Decode> for Identity { type Error = core::convert::Infallible; fn decode(bytes: &[u8]) -> Result, Self::Error> { Ok(bytes.to_vec()) } } impl Decode<[u8; N]> for Identity { type Error = IdentityDecodeError; fn decode(bytes: &[u8]) -> Result<[u8; N], Self::Error> { bytes.try_into().map_err(|_| IdentityDecodeError { expected: N, actual: bytes.len(), }) } } impl Canonical for Identity {} /// A relaxed codec marker that tracks the underlying format without requiring encoding. /// /// Use this for deserialized values where you know the codec but don't have /// (or don't need) the encoder implementation. /// /// # Example /// /// ``` /// # #[cfg(feature = "sha2")] /// # { /// use evidence::digest::{Digest, DigestUnchecked, sha2::Sha256}; /// use evidence::codec::Relaxed; /// use hybrid_array::Array; /// /// // You received a digest over the network, encoded as CBOR /// enum Cbor {} /// /// let bytes: Array = Array::try_from([0u8; 32].as_slice()).unwrap(); /// /// // Use Relaxed to track the format without needing Encode impl /// let digest: Digest> = Digest::from_unchecked_array(bytes); /// /// // This would NOT compile — Relaxed doesn't implement Encode: /// // let d: Digest> = Digest::hash(&my_string); /// # } /// ``` #[derive(Debug)] pub struct Relaxed(core::marker::PhantomData);