scale_compressed/
lib.rs

1// SPDX-License-Identifier: GPL-3.0 OR Apache-2.0
2
3//! Crate to compress [SCALE](https://crates.io/crates/parity-scale-codec) encoded data.
4//!
5//! This crate is useful for compressing data that is sent over the network.
6//!
7//! # Example
8//!
9//! ```rust
10//! use scale_compressed::ScaleCompressed;
11//! use parity_scale_codec::{Encode, Decode};
12//!
13//! let compressed = ScaleCompressed::new(vec![1u8, 2, 3, 4, 5]);
14//! let encoded = compressed.encode();
15//! let decoded = ScaleCompressed::<Vec<u8>>::decode(&mut &encoded[..]).unwrap();
16//! assert_eq!(vec![1, 2, 3, 4, 5], decoded.0);
17//! ```
18
19// No std support
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use parity_scale_codec::{Decode, Encode, Error, Input, Output};
23extern crate alloc;
24use alloc::vec::Vec;
25
26/// Wrap a struct to be compressed for encoding.
27pub struct ScaleCompressed<T>(pub T);
28
29impl<T> ScaleCompressed<T> {
30	pub fn new(inner: T) -> Self {
31		Self(inner)
32	}
33}
34
35impl<T: Encode> Encode for ScaleCompressed<T> {
36	fn encode_to<O: Output + ?Sized>(&self, output: &mut O) {
37		let compressed: Vec<u8> =
38			self.0.using_encoded(|buf| miniz_oxide::deflate::compress_to_vec(buf, 6));
39		compressed.encode_to(output); // Double encode for the length prefix
40	}
41}
42
43impl<T: Decode> Decode for ScaleCompressed<T> {
44	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
45		let compressed = Vec::<u8>::decode(input)?;
46		let decompressed =
47			miniz_oxide::inflate::decompress_to_vec_with_limit(&compressed, 4 * 1024 * 1024)
48				.map_err(|_| Error::from("Data corrupted"))?;
49		drop(compressed);
50
51		T::decode(&mut &decompressed[..]).map(Self)
52	}
53}
54
55#[cfg(test)]
56mod tests {
57	use super::*;
58	use std::fmt::Debug;
59
60	#[test]
61	fn test_encode_decode() {
62		test_works(vec![0; 0]);
63		test_works(vec![1, 2, 3, 4, 5]);
64
65		test_works(None::<u8>);
66		test_works(Some(1));
67		test_works(Some(vec![1, 2, 3, 4, 5]));
68		test_works(Some(vec![0; 0]));
69
70		test_works(1);
71		test_works(1u8);
72		test_works(1u16);
73		test_works(1u32);
74		test_works(1u64);
75		test_works(1u128);
76
77		test_works(true);
78		test_works(false);
79
80		test_works("hey".to_string());
81	}
82
83	fn test_works<T: Encode + Decode + Clone + PartialEq + Debug>(original: T) {
84		let compressed = ScaleCompressed::new(original.clone());
85		let encoded = compressed.encode();
86		let decoded = ScaleCompressed::<T>::decode(&mut &encoded[..]).unwrap();
87		assert_eq!(original, decoded.0);
88	}
89}