Skip to main content

typub_storage/
encoding.rs

1//! Encoding utilities for asset data.
2
3use std::path::Path;
4
5/// Encode binary data to base64 data URI
6pub fn to_data_uri(data: &[u8], path: &Path) -> String {
7    let mime = crate::mime_type_from_path(path);
8    let b64 = base64_encode(data);
9    format!("data:{};base64,{}", mime, b64)
10}
11
12/// Simple base64 encoding
13pub fn base64_encode(data: &[u8]) -> String {
14    const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
15
16    let mut result = String::new();
17    for chunk in data.chunks(3) {
18        let mut val = 0u32;
19        for (i, &byte) in chunk.iter().enumerate() {
20            val |= (byte as u32) << (16 - 8 * i);
21        }
22
23        let chars = match chunk.len() {
24            1 => 2,
25            2 => 3,
26            _ => 4,
27        };
28
29        for i in 0..chars {
30            let idx = ((val >> (18 - 6 * i)) & 0x3F) as usize;
31            result.push(ALPHABET[idx] as char);
32        }
33
34        for _ in chars..4 {
35            result.push('=');
36        }
37    }
38
39    result
40}
41
42#[cfg(test)]
43mod tests {
44    #![allow(clippy::expect_used)]
45    use super::*;
46
47    #[test]
48    fn test_base64_encode_empty() {
49        assert_eq!(base64_encode(&[]), "");
50    }
51
52    #[test]
53    fn test_base64_encode_hello() {
54        // "Hello" -> "SGVsbG8="
55        assert_eq!(base64_encode(b"Hello"), "SGVsbG8=");
56    }
57
58    #[test]
59    fn test_base64_encode_padding() {
60        // "a" -> "YQ=="
61        assert_eq!(base64_encode(b"a"), "YQ==");
62        // "ab" -> "YWI="
63        assert_eq!(base64_encode(b"ab"), "YWI=");
64        // "abc" -> "YWJj"
65        assert_eq!(base64_encode(b"abc"), "YWJj");
66    }
67
68    #[test]
69    fn test_to_data_uri() {
70        let data = b"test";
71        let path = Path::new("image.png");
72        let uri = to_data_uri(data, path);
73        assert!(uri.starts_with("data:image/png;base64,"));
74    }
75}