base_d/
convenience.rs

1//! Convenience functions for common encoding patterns.
2//!
3//! These functions combine hashing/compression with encoding in a single call,
4//! using random dictionary selection for varied output.
5
6use crate::{CompressionAlgorithm, DictionaryRegistry, HashAlgorithm, compress, encode, hash};
7
8/// Result of a hash + encode operation.
9#[derive(Debug, Clone)]
10pub struct HashEncodeResult {
11    /// The encoded output
12    pub encoded: String,
13    /// The hash algorithm used
14    pub hash_algo: HashAlgorithm,
15    /// Name of the dictionary used for encoding
16    pub dictionary_name: String,
17}
18
19/// Result of a compress + encode operation.
20#[derive(Debug, Clone)]
21pub struct CompressEncodeResult {
22    /// The encoded output
23    pub encoded: String,
24    /// The compression algorithm used
25    pub compress_algo: CompressionAlgorithm,
26    /// Name of the dictionary used for encoding
27    pub dictionary_name: String,
28}
29
30/// Hash data with a random algorithm and encode with a random dictionary.
31///
32/// # Example
33/// ```
34/// use base_d::{DictionaryRegistry, convenience::hash_encode};
35///
36/// let registry = DictionaryRegistry::load_default().unwrap();
37/// let result = hash_encode(b"Hello, world!", &registry).unwrap();
38/// println!("Encoded: {}", result.encoded);
39/// println!("Hash: {}", result.hash_algo.as_str());
40/// println!("Dictionary: {}", result.dictionary_name);
41/// ```
42pub fn hash_encode(
43    data: &[u8],
44    registry: &DictionaryRegistry,
45) -> Result<HashEncodeResult, Box<dyn std::error::Error>> {
46    let algo = HashAlgorithm::random();
47    hash_encode_with(data, algo, registry)
48}
49
50/// Hash data with a specific algorithm and encode with a random dictionary.
51pub fn hash_encode_with(
52    data: &[u8],
53    algo: HashAlgorithm,
54    registry: &DictionaryRegistry,
55) -> Result<HashEncodeResult, Box<dyn std::error::Error>> {
56    let hashed = hash(data, algo);
57    let (dict_name, dict) = registry.random()?;
58    let encoded = encode(&hashed, &dict);
59
60    Ok(HashEncodeResult {
61        encoded,
62        hash_algo: algo,
63        dictionary_name: dict_name,
64    })
65}
66
67/// Compress data with a random algorithm and encode with a random dictionary.
68///
69/// # Example
70/// ```
71/// use base_d::{DictionaryRegistry, convenience::compress_encode};
72///
73/// let registry = DictionaryRegistry::load_default().unwrap();
74/// let result = compress_encode(b"Hello, world!", &registry).unwrap();
75/// println!("Encoded: {}", result.encoded);
76/// println!("Compression: {}", result.compress_algo.as_str());
77/// println!("Dictionary: {}", result.dictionary_name);
78/// ```
79pub fn compress_encode(
80    data: &[u8],
81    registry: &DictionaryRegistry,
82) -> Result<CompressEncodeResult, Box<dyn std::error::Error>> {
83    let algo = CompressionAlgorithm::random();
84    compress_encode_with(data, algo, registry)
85}
86
87/// Compress data with a specific algorithm and encode with a random dictionary.
88pub fn compress_encode_with(
89    data: &[u8],
90    algo: CompressionAlgorithm,
91    registry: &DictionaryRegistry,
92) -> Result<CompressEncodeResult, Box<dyn std::error::Error>> {
93    let level = algo.default_level();
94    let compressed = compress(data, algo, level)?;
95    let (dict_name, dict) = registry.random()?;
96    let encoded = encode(&compressed, &dict);
97
98    Ok(CompressEncodeResult {
99        encoded,
100        compress_algo: algo,
101        dictionary_name: dict_name,
102    })
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_hash_encode() {
111        let registry = DictionaryRegistry::load_default().unwrap();
112        let result = hash_encode(b"test data", &registry).unwrap();
113        assert!(!result.encoded.is_empty());
114        assert!(!result.dictionary_name.is_empty());
115    }
116
117    #[test]
118    fn test_compress_encode() {
119        let registry = DictionaryRegistry::load_default().unwrap();
120        let result = compress_encode(b"test data for compression", &registry).unwrap();
121        assert!(!result.encoded.is_empty());
122        assert!(!result.dictionary_name.is_empty());
123    }
124
125    #[test]
126    fn test_hash_encode_with_specific_algo() {
127        let registry = DictionaryRegistry::load_default().unwrap();
128        let result = hash_encode_with(b"test", HashAlgorithm::Sha256, &registry).unwrap();
129        assert_eq!(result.hash_algo, HashAlgorithm::Sha256);
130    }
131
132    #[test]
133    fn test_compress_encode_with_specific_algo() {
134        let registry = DictionaryRegistry::load_default().unwrap();
135        let result =
136            compress_encode_with(b"test data", CompressionAlgorithm::Gzip, &registry).unwrap();
137        assert_eq!(result.compress_algo, CompressionAlgorithm::Gzip);
138    }
139
140    #[test]
141    fn test_random_hash() {
142        // Just verify it doesn't panic and returns valid algorithms
143        for _ in 0..10 {
144            let algo = HashAlgorithm::random();
145            assert!(HashAlgorithm::all().contains(&algo));
146        }
147    }
148
149    #[test]
150    fn test_random_compress() {
151        // Just verify it doesn't panic and returns valid algorithms
152        for _ in 0..10 {
153            let algo = CompressionAlgorithm::random();
154            assert!(CompressionAlgorithm::all().contains(&algo));
155        }
156    }
157}