Skip to main content

reifydb_type/value/blob/
base58.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use super::Blob;
5use crate::{
6	error::{BlobEncodingKind, Error, TypeError},
7	fragment::Fragment,
8	util::base58,
9};
10
11impl Blob {
12	pub fn from_b58(fragment: Fragment) -> Result<Self, Error> {
13		let b58_str = fragment.text();
14		match base58::decode(b58_str) {
15			Ok(bytes) => Ok(Blob::new(bytes)),
16			Err(_) => Err(TypeError::BlobEncoding {
17				kind: BlobEncodingKind::InvalidBase58,
18				message: format!("Invalid base58 string: '{}'", fragment.text()),
19				fragment,
20			}
21			.into()),
22		}
23	}
24
25	pub fn to_b58(&self) -> String {
26		base58::encode(self.as_bytes())
27	}
28}
29
30#[cfg(test)]
31pub mod tests {
32	use super::*;
33	use crate::fragment::Fragment;
34
35	#[test]
36	fn test_from_b58() {
37		let blob = Blob::from_b58(Fragment::testing("9Ajdvzr")).unwrap();
38		assert_eq!(blob.as_bytes(), b"Hello");
39	}
40
41	#[test]
42	fn test_from_b58_empty() {
43		let blob = Blob::from_b58(Fragment::testing("")).unwrap();
44		assert_eq!(blob.as_bytes(), b"");
45	}
46
47	#[test]
48	fn test_from_b58_invalid() {
49		// '0', 'O', 'I', 'l' are not in base58 alphabet
50		let result = Blob::from_b58(Fragment::testing("0invalid"));
51		assert!(result.is_err());
52
53		let result = Blob::from_b58(Fragment::testing("Oops"));
54		assert!(result.is_err());
55
56		let result = Blob::from_b58(Fragment::testing("Invalid!"));
57		assert!(result.is_err());
58	}
59
60	#[test]
61	fn test_to_b58() {
62		let blob = Blob::new(b"Hello".to_vec());
63		assert_eq!(blob.to_b58(), "9Ajdvzr");
64	}
65
66	#[test]
67	fn test_to_b58_empty() {
68		let blob = Blob::new(vec![]);
69		assert_eq!(blob.to_b58(), "");
70	}
71
72	#[test]
73	fn test_b58_roundtrip() {
74		let original = b"Hello, World! \x00\x01\x02\xFF";
75		let blob = Blob::new(original.to_vec());
76		let b58_str = blob.to_b58();
77		let decoded = Blob::from_b58(Fragment::testing(&b58_str)).unwrap();
78		assert_eq!(decoded.as_bytes(), original);
79	}
80
81	#[test]
82	fn test_b58_binary_data() {
83		let data = vec![0xde, 0xad, 0xbe, 0xef];
84		let blob = Blob::new(data.clone());
85		let b58_str = blob.to_b58();
86		let decoded = Blob::from_b58(Fragment::testing(&b58_str)).unwrap();
87		assert_eq!(decoded.as_bytes(), &data);
88	}
89
90	#[test]
91	fn test_b58_leading_zeros() {
92		// Leading zero bytes become leading '1's
93		let data = vec![0, 0, 1];
94		let blob = Blob::new(data.clone());
95		let b58_str = blob.to_b58();
96		assert_eq!(b58_str, "112");
97		let decoded = Blob::from_b58(Fragment::testing(&b58_str)).unwrap();
98		assert_eq!(decoded.as_bytes(), &data);
99	}
100}