Skip to main content

doido_cache/
codec.rs

1//! Cache value serialization with optional compression (Rails cache
2//! `:compress`/serializer options). Values are serialized to JSON bytes and,
3//! when requested, gzip-compressed — worthwhile for large or repetitive entries.
4
5use doido_core::Result;
6use flate2::read::GzDecoder;
7use flate2::write::GzEncoder;
8use flate2::Compression;
9use serde_json::Value;
10use std::io::{Read, Write};
11
12/// Serialize `value` to JSON bytes, gzip-compressing when `compress` is set.
13pub fn encode(value: &Value, compress: bool) -> Vec<u8> {
14    let json = serde_json::to_vec(value).unwrap_or_default();
15    if compress {
16        gzip(&json)
17    } else {
18        json
19    }
20}
21
22/// Decode bytes produced by [`encode`] (must use the same `compressed` flag).
23pub fn decode(bytes: &[u8], compressed: bool) -> Result<Value> {
24    let json = if compressed {
25        gunzip(bytes)?
26    } else {
27        bytes.to_vec()
28    };
29    serde_json::from_slice(&json)
30        .map_err(|e| doido_core::anyhow::anyhow!("cache decode failed: {e}"))
31}
32
33fn gzip(data: &[u8]) -> Vec<u8> {
34    let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
35    let _ = encoder.write_all(data);
36    encoder.finish().unwrap_or_default()
37}
38
39fn gunzip(data: &[u8]) -> Result<Vec<u8>> {
40    let mut decoder = GzDecoder::new(data);
41    let mut out = Vec::new();
42    decoder
43        .read_to_end(&mut out)
44        .map_err(|e| doido_core::anyhow::anyhow!("gunzip failed: {e}"))?;
45    Ok(out)
46}