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