use alloc::string::{String, ToString};
use snafu::prelude::*;
use crate::ByteArray;
pub trait Base58 {
fn from_base58(hex: &str) -> Result<Self, Base58Error>
where Self: Sized;
fn to_base58(&self) -> String;
}
#[derive(Debug, Snafu)]
#[allow(missing_docs)]
pub enum Base58Error {
#[snafu(display("Byte array error: `{reason}'"))]
ByteArrayError { reason: String },
#[snafu(display("Decode error: `{reason}'"))]
DecodeError { reason: String },
}
impl<T: ByteArray> Base58 for T {
fn from_base58(data: &str) -> Result<Self, Base58Error>
where Self: Sized {
let bytes = base58_monero::decode(data).map_err(|e| Base58Error::DecodeError { reason: e.to_string() })?;
Self::from_bytes(&bytes).map_err(|e| Base58Error::ByteArrayError { reason: e.to_string() })
}
fn to_base58(&self) -> String {
base58_monero::encode(self.as_bytes()).expect("base58_monero::encode is infallible")
}
}
#[cfg(test)]
mod test {
use alloc::vec::Vec;
use rand::{rngs::OsRng, RngCore};
use super::*;
#[test]
fn decoding() {
assert_eq!(Vec::from_base58("111111").unwrap(), vec![0; 4]);
assert_eq!(Vec::from_base58("11115Q").unwrap(), vec![0, 0, 0, 255]);
assert!(Vec::from_base58("11111O").is_err());
assert!(Vec::from_base58("🖖🥴").is_err());
}
#[test]
fn encoding() {
assert_eq!(vec![0; 4].to_base58(), "111111");
assert_eq!(vec![0, 2, 250, 39].to_base58(), "111zzz");
}
#[test]
fn inverse_operations() {
let mut bytes = vec![0; 10];
OsRng.fill_bytes(&mut bytes);
assert_eq!(Vec::from_base58(&bytes.to_base58()).unwrap(), bytes);
}
}