libvctrl_handler 4.4.0

Fundamental contracts for building a version control system – no implementations, only traits and types
Documentation
//! Deserialization of version control objects from byte slices.

use crate::errors::VctrlError;
use crate::types::blob::Blob;
use crate::types::commit::Commit;
use crate::types::tag::Tag;
use crate::types::tree::Tree;

/// Defines the interface for deserializing version control objects.
///
/// # Purpose
///
/// A `Decoder` translates byte vectors back into in-memory data structures.
/// It is the inverse of [`Encoder`].
///
/// # Design Rationale
///
/// Decoding can fail due to corrupted data, malformed inputs, or version
/// mismatches, hence every method returns a `Result` with [`VctrlError`].
///
/// # Examples
///
/// ```
/// use libvctrl_handler::{Blob, Commit, Decoder, Hash, Tag, Tree, UserID, VctrlError};
///
/// struct DummyDecoder;
/// impl Decoder for DummyDecoder {
///     fn decode_blob(&self, data: &[u8]) -> Result<Blob, VctrlError> {
///         Ok(Blob::new(data.to_vec()))
///     }
///     fn decode_tree(&self, _data: &[u8]) -> Result<Tree, VctrlError> { Tree::new(vec![]) }
///     fn decode_commit(&self, _data: &[u8]) -> Result<Commit, VctrlError> {
///         let tree = Hash::from_bytes(&[0u8; 64])?;
///         let user = UserID::new("a".to_string(), "b".to_string())?;
///         Ok(Commit::new(tree, vec![], user.clone(), user, String::new()))
///     }
///     fn decode_tag(&self, _data: &[u8]) -> Result<Tag, VctrlError> {
///         let target = Hash::from_bytes(&[0u8; 64])?;
///         Tag::new("tag".to_string(), target, None, String::new())
///     }
/// }
///
/// let decoder = DummyDecoder;
/// let blob = decoder.decode_blob(b"data").unwrap();
/// assert_eq!(blob.data(), b"data");
/// ```
pub trait Decoder {
    /// Decodes a byte slice into a [`Blob`].
    ///
    /// # Errors
    ///
    /// Returns [`VctrlError::CorruptedData`] if the bytes are malformed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use libvctrl_handler::{Blob, Commit, Decoder, Hash, Tag, Tree, UserID, VctrlError};
    /// # struct DecoderImpl;
    /// # impl Decoder for DecoderImpl {
    /// #     fn decode_blob(&self, d: &[u8]) -> Result<Blob, VctrlError> { Ok(Blob::new(d.to_vec())) }
    /// #     fn decode_tree(&self, _d: &[u8]) -> Result<Tree, VctrlError> { Tree::new(vec![]) }
    /// #     fn decode_commit(&self, _d: &[u8]) -> Result<Commit, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; let u = UserID::new("a".to_string(), "b".to_string())?; Ok(Commit::new(t, vec![], u.clone(), u, String::new())) }
    /// #     fn decode_tag(&self, _d: &[u8]) -> Result<Tag, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; Tag::new("t".to_string(), t, None, String::new()) }
    /// # }
    /// let decoder = DecoderImpl;
    /// let blob = decoder.decode_blob(b"data").unwrap();
    /// assert_eq!(blob.size(), 4);
    /// ```
    fn decode_blob(&self, data: &[u8]) -> Result<Blob, VctrlError>;

    /// Decodes a byte slice into a [`Tree`].
    ///
    /// # Errors
    ///
    /// Returns [`VctrlError::CorruptedData`] if the bytes are malformed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use libvctrl_handler::{Blob, Commit, Decoder, Hash, Tag, Tree, UserID, VctrlError};
    /// # struct DecoderImpl;
    /// # impl Decoder for DecoderImpl {
    /// #     fn decode_blob(&self, _d: &[u8]) -> Result<Blob, VctrlError> { Ok(Blob::new(vec![])) }
    /// #     fn decode_tree(&self, _d: &[u8]) -> Result<Tree, VctrlError> { Tree::new(vec![]) }
    /// #     fn decode_commit(&self, _d: &[u8]) -> Result<Commit, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; let u = UserID::new("a".to_string(), "b".to_string())?; Ok(Commit::new(t, vec![], u.clone(), u, String::new())) }
    /// #     fn decode_tag(&self, _d: &[u8]) -> Result<Tag, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; Tag::new("t".to_string(), t, None, String::new()) }
    /// # }
    /// let decoder = DecoderImpl;
    /// let tree = decoder.decode_tree(b"").unwrap();
    /// assert!(tree.entries().is_empty());
    /// ```
    fn decode_tree(&self, data: &[u8]) -> Result<Tree, VctrlError>;

    /// Decodes a byte slice into a [`Commit`].
    ///
    /// # Errors
    ///
    /// Returns [`VctrlError::CorruptedData`] if the bytes are malformed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use libvctrl_handler::{Blob, Commit, Decoder, Hash, Tag, Tree, UserID, VctrlError};
    /// # struct DecoderImpl;
    /// # impl Decoder for DecoderImpl {
    /// #     fn decode_blob(&self, _d: &[u8]) -> Result<Blob, VctrlError> { Ok(Blob::new(vec![])) }
    /// #     fn decode_tree(&self, _d: &[u8]) -> Result<Tree, VctrlError> { Tree::new(vec![]) }
    /// #     fn decode_commit(&self, _d: &[u8]) -> Result<Commit, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; let u = UserID::new("a".to_string(), "b".to_string())?; Ok(Commit::new(t, vec![], u.clone(), u, String::new())) }
    /// #     fn decode_tag(&self, _d: &[u8]) -> Result<Tag, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; Tag::new("t".to_string(), t, None, String::new()) }
    /// # }
    /// let decoder = DecoderImpl;
    /// let commit = decoder.decode_commit(b"").unwrap();
    /// assert_eq!(commit.message(), "");
    /// ```
    fn decode_commit(&self, data: &[u8]) -> Result<Commit, VctrlError>;

    /// Decodes a byte slice into a [`Tag`].
    ///
    /// # Errors
    ///
    /// Returns [`VctrlError::CorruptedData`] if the bytes are malformed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use libvctrl_handler::{Blob, Commit, Decoder, Hash, Tag, Tree, UserID, VctrlError};
    /// # struct DecoderImpl;
    /// # impl Decoder for DecoderImpl {
    /// #     fn decode_blob(&self, _d: &[u8]) -> Result<Blob, VctrlError> { Ok(Blob::new(vec![])) }
    /// #     fn decode_tree(&self, _d: &[u8]) -> Result<Tree, VctrlError> { Tree::new(vec![]) }
    /// #     fn decode_commit(&self, _d: &[u8]) -> Result<Commit, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; let u = UserID::new("a".to_string(), "b".to_string())?; Ok(Commit::new(t, vec![], u.clone(), u, String::new())) }
    /// #     fn decode_tag(&self, _d: &[u8]) -> Result<Tag, VctrlError> { let t = Hash::from_bytes(&[0u8; 64])?; Tag::new("t".to_string(), t, None, String::new()) }
    /// # }
    /// let decoder = DecoderImpl;
    /// let tag = decoder.decode_tag(b"").unwrap();
    /// assert_eq!(tag.name(), "t");
    /// ```
    fn decode_tag(&self, data: &[u8]) -> Result<Tag, VctrlError>;
}