Skip to main content

reifydb_type/value/blob/
base58.rs

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