Skip to main content

yaml_edit/scalar/
binary.rs

1//! Binary (`!!binary`) scalars and their base64 encoding.
2
3use base64::{engine::general_purpose, Engine as _};
4
5use super::{ScalarStyle, ScalarType, ScalarValue};
6
7/// Base64 encode bytes for binary data
8fn base64_encode(input: &[u8]) -> String {
9    general_purpose::STANDARD.encode(input)
10}
11
12/// Base64 decode string back to bytes
13pub(super) fn base64_decode(input: &str) -> Result<Vec<u8>, String> {
14    general_purpose::STANDARD
15        .decode(input.trim())
16        .map_err(|e| format!("Base64 decode error: {e}"))
17}
18
19impl ScalarValue {
20    /// Create a binary scalar from raw bytes
21    pub fn binary(data: &[u8]) -> Self {
22        let encoded = base64_encode(data);
23        Self {
24            value: encoded,
25            style: ScalarStyle::Plain,
26            scalar_type: ScalarType::Binary,
27            tag: None,
28        }
29    }
30
31    /// Extract binary data if this is a binary scalar
32    pub fn as_binary(&self) -> Option<Result<Vec<u8>, String>> {
33        match self.scalar_type {
34            ScalarType::Binary => Some(base64_decode(&self.value)),
35            _ => None,
36        }
37    }
38
39    /// Check if this is a binary scalar
40    pub fn is_binary(&self) -> bool {
41        self.scalar_type == ScalarType::Binary
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[test]
50    fn test_binary_data_encoding() {
51        // Test creating binary scalar from raw bytes
52        let data = b"Hello, World!";
53        let scalar = ScalarValue::binary(data);
54
55        assert!(scalar.is_binary());
56        assert_eq!(scalar.scalar_type(), ScalarType::Binary);
57
58        // Should produce valid base64
59        let yaml_output = scalar.to_yaml_string();
60        assert!(yaml_output.starts_with("!!binary "));
61
62        // Should be able to decode back to original data
63        if let Some(decoded_result) = scalar.as_binary() {
64            let decoded = decoded_result.expect("Should decode successfully");
65            assert_eq!(decoded, data);
66        } else {
67            panic!("Should be able to extract binary data");
68        }
69    }
70
71    #[test]
72    fn test_base64_encoding_decoding() {
73        // Test various byte sequences
74        let test_cases = [
75            b"".as_slice(),
76            b"A",
77            b"AB",
78            b"ABC",
79            b"ABCD",
80            b"Hello, World!",
81            &[0, 1, 2, 3, 255, 254, 253],
82        ];
83
84        for data in test_cases {
85            let encoded = base64_encode(data);
86            let decoded = base64_decode(&encoded).expect("Should decode successfully");
87            assert_eq!(decoded, data, "Failed for data: {:?}", data);
88        }
89    }
90}