titan-api-codec 1.2.9

Helpers for encoding and decoding Titan API messages
Documentation
//! Defines transforms that utilize [gzip] to compress and decompress data.
//!
//! [gzip]: https://www.gzip.org/

use super::common::BinaryTransform;

use std::io::prelude::*;

use bytes::{Buf, Bytes};
use flate2::bufread::{GzDecoder, GzEncoder};
use flate2::Compression;

/// Transform that applies gzip compression to the input.
#[derive(Default)]
pub struct GzipCompressor {
    level: Compression,
}

impl GzipCompressor {
    /// Creates a new Gzip compressor with the given compression level.
    pub fn new(level: Compression) -> Self {
        Self { level }
    }
}

impl BinaryTransform for GzipCompressor {
    fn transform(&self, data: Bytes) -> Result<Bytes, std::io::Error> {
        let mut enc = GzEncoder::new(data.reader(), self.level);
        let mut buffer = Vec::new();
        enc.read_to_end(&mut buffer)?;
        Ok(buffer.into())
    }
}

/// Transform that takes gzip-compressed data and inflates it back to its original content.
#[derive(Default)]
pub struct GzipDecompressor {}

impl BinaryTransform for GzipDecompressor {
    fn transform(&self, data: Bytes) -> Result<Bytes, std::io::Error> {
        let mut dec = GzDecoder::new(data.reader());
        let mut buffer = Vec::new();
        dec.read_to_end(&mut buffer)?;
        Ok(buffer.into())
    }
}

#[cfg(test)]
mod test {
    use super::{GzipCompressor, GzipDecompressor};
    use crate::transform::BinaryTransform;
    use bytes::Bytes;
    use lipsum::lipsum;

    #[test]
    fn test_roundtrip_default() {
        let compressor = GzipCompressor::default();
        let decompressor = GzipDecompressor::default();

        let data = Bytes::from(lipsum(1000));

        let compressed = compressor
            .transform(data.clone())
            .expect("should compress via zstd");
        let uncompressed = decompressor
            .transform(compressed)
            .expect("should decompress from zstd");

        assert_eq!(data, uncompressed);
    }
}