reifydb_type/value/blob/
base64.rs1use super::Blob;
5use crate::{
6 error::{BlobEncodingKind, Error, TypeError},
7 fragment::Fragment,
8 util::base64::engine::general_purpose,
9};
10
11impl Blob {
12 pub fn from_b64(fragment: Fragment) -> Result<Self, Error> {
13 let b64_str = fragment.text();
14
15 match general_purpose::STANDARD.decode(b64_str) {
16 Ok(bytes) => Ok(Blob::new(bytes)),
17 Err(_) => match general_purpose::STANDARD_NO_PAD.decode(b64_str) {
18 Ok(bytes) => Ok(Blob::new(bytes)),
19 Err(_) => Err(TypeError::BlobEncoding {
20 kind: BlobEncodingKind::InvalidBase64,
21 message: format!("Invalid base64 string: '{}'", fragment.text()),
22 fragment,
23 }
24 .into()),
25 },
26 }
27 }
28
29 pub fn from_b64url(fragment: Fragment) -> Result<Self, Error> {
30 let b64url_str = fragment.text();
31 match general_purpose::URL_SAFE_NO_PAD.decode(b64url_str) {
32 Ok(bytes) => Ok(Blob::new(bytes)),
33 Err(_) => Err(TypeError::BlobEncoding {
34 kind: BlobEncodingKind::InvalidBase64Url,
35 message: format!("Invalid base64url string: '{}'", fragment.text()),
36 fragment,
37 }
38 .into()),
39 }
40 }
41
42 pub fn to_b64(&self) -> String {
43 general_purpose::STANDARD.encode(self.as_bytes())
44 }
45
46 pub fn to_b64url(&self) -> String {
47 general_purpose::URL_SAFE_NO_PAD.encode(self.as_bytes())
48 }
49}
50
51#[cfg(test)]
52pub mod tests {
53 use super::*;
54 use crate::fragment::Fragment;
55
56 #[test]
57 fn test_from_b64() {
58 let blob = Blob::from_b64(Fragment::testing("SGVsbG8=")).unwrap();
59 assert_eq!(blob.as_bytes(), b"Hello");
60 }
61
62 #[test]
63 fn test_from_b64_no_padding() {
64 let blob = Blob::from_b64(Fragment::testing("SGVsbG8")).unwrap();
65 assert_eq!(blob.as_bytes(), b"Hello");
66 }
67
68 #[test]
69 fn test_from_b64_empty() {
70 let blob = Blob::from_b64(Fragment::testing("")).unwrap();
71 assert_eq!(blob.as_bytes(), b"");
72 }
73
74 #[test]
75 fn test_from_b64_invalid() {
76 let result = Blob::from_b64(Fragment::testing("!!!invalid!!!"));
77 assert!(result.is_err());
78 }
79
80 #[test]
81 fn test_from_b64url() {
82 let blob = Blob::from_b64url(Fragment::testing("SGVsbG8")).unwrap();
83 assert_eq!(blob.as_bytes(), b"Hello");
84 }
85
86 #[test]
87 fn test_from_b64url_invalid() {
88 let result = Blob::from_b64url(Fragment::testing("SGVsbG8=")); assert!(result.is_err());
90 }
91
92 #[test]
93 fn test_to_b64() {
94 let blob = Blob::new(b"Hello".to_vec());
95 assert_eq!(blob.to_b64(), "SGVsbG8=");
96 }
97
98 #[test]
99 fn test_to_b64url() {
100 let blob = Blob::new(b"Hello".to_vec());
101 assert_eq!(blob.to_b64url(), "SGVsbG8");
102 }
103
104 #[test]
105 fn test_b64_roundtrip() {
106 let original = b"Hello, World! \x00\x01\x02\xFF";
107 let blob = Blob::new(original.to_vec());
108 let b64_str = blob.to_b64();
109 let decoded = Blob::from_b64(Fragment::testing(&b64_str)).unwrap();
110 assert_eq!(decoded.as_bytes(), original);
111 }
112
113 #[test]
114 fn test_b64url_roundtrip() {
115 let original = b"Hello, World! \x00\x01\x02\xFF";
116 let blob = Blob::new(original.to_vec());
117 let b64url_str = blob.to_b64url();
118 let decoded = Blob::from_b64url(Fragment::testing(&b64url_str)).unwrap();
119 assert_eq!(decoded.as_bytes(), original);
120 }
121}