azathoth_transformers 0.1.0

Data transformers for the AzathothC2 project
Documentation
use crate::{Transformer, TransformerError, TransformerExt};
use alloc::boxed::Box;
use alloc::vec::Vec;

/// A [`Transformer`] pipeline
///
/// Simplifies the transformation code when multiple transformers are in play.
/// It is important to know that order is *kept* when adding a transformer.
/// For example, adding an [`AppendTransformer`](crate::basic::AppendTransformer) first, and then adding a [`PrependTransformer`](crate::basic::PrependTransformer), would apply the appender first, and then the prepender.
/// For the reverse operation, it'll run [`AppendTransformer::reverse(...)`] first, and then it'll call [`PrependTransformer::reverse(...)`].
///
/// [`TransformerPipeline::apply(...)`] order:
/// 1. [`AppendTransformer::apply(...)`]
/// 2. [`PrependTransformer::apply(...)`]
///
/// [`TransformerPipeline::reverse(...)`] order:
/// 1. [`PrependTransformer::reverse(...)`]
/// 2. [`AppendTransformer::reverse(...)`]
///
/// ## Example Usage:
/// ```
/// use transformers::{AppendTransformer, Transformer, TransformerError, TransformerExt, TransformerPipeline, PrependTransformer};
/// fn main() -> Result<(), TransformerError> {
///     let data = "bar ";
///     let suffix = "baz";
///     let prefix = "foo ";
///     let mut pipeline = TransformerPipeline::new();
///     pipeline.add(AppendTransformer::new(suffix));
///     pipeline.add(PrependTransformer::new(prefix));
///     let modified = pipeline.apply(data)?;
///     assert_eq!(b"foo bar baz", modified.as_slice());
///     let reversed = pipeline.reverse(modified)?;
///     assert_eq!(b"bar ", reversed.as_slice());
///     Ok(())
/// }
/// ```
#[derive(Default)]
pub struct TransformerPipeline {
    transformers: Vec<Box<dyn Transformer>>,
}
impl TransformerPipeline {
    /// Creates a new pipeline
    #[must_use]
    pub fn new() -> TransformerPipeline {
        Self {
            transformers: Vec::new(),
        }
    }

    /// Pushes a new transformer to the pipeline.
    pub fn add<T>(&mut self, transformer: T)
    where
        T: Transformer + 'static,
    {
        self.transformers.push(Box::new(transformer));
    }

    /// Applies the transformers in the pipeline to the given data.
    ///
    /// # Errors
    /// Returns an error if any of the transformers returned an error during the application
    pub fn apply(&mut self, data: impl AsRef<[u8]>) -> Result<Vec<u8>, TransformerError> {
        let mut buf = data.as_ref().to_vec();
        for transformer in &mut self.transformers {
            buf = transformer.apply(&buf)?;
        }
        Ok(buf)
    }

    /// Reverses the application transformations in the pipeline
    /// # Errors
    /// Returns an error if any of the transformers returned an error during the reversal process
    pub fn reverse(&mut self, data: impl AsRef<[u8]>) -> Result<Vec<u8>, TransformerError> {
        let mut buf = data.as_ref().to_vec();
        for transformer in self.transformers.iter_mut().rev() {
            buf = transformer.reverse_bytes(&buf)?;
        }
        Ok(buf)
    }
}

impl Clone for TransformerPipeline {
    fn clone(&self) -> Self {
        let transformers = self.transformers.iter().map(|p| p.box_clone()).collect();
        Self { transformers }
    }
}