#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
use crate::{Base, Error, Result};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EncodedString {
base: Base,
inner: String,
}
impl EncodedString {
pub fn new<S: Into<String>>(s: S) -> Result<Self> {
let inner = s.into();
let code = inner.chars().next().ok_or(Error::EmptyInput)?;
let base = Base::from_code(code)?;
Ok(Self { base, inner })
}
pub fn base(&self) -> Base {
self.base
}
pub fn as_str(&self) -> &str {
&self.inner
}
pub fn decode(&self) -> Result<Vec<u8>> {
let code_len = self.base.code().len_utf8();
self.base.decode(&self.inner[code_len..], true)
}
pub fn decode_with_strictness(&self, strict: bool) -> Result<Vec<u8>> {
let code_len = self.base.code().len_utf8();
self.base.decode(&self.inner[code_len..], strict)
}
pub fn into_inner(self) -> String {
self.inner
}
}
impl AsRef<str> for EncodedString {
fn as_ref(&self) -> &str {
&self.inner
}
}
impl core::fmt::Display for EncodedString {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.inner)
}
}
impl core::str::FromStr for EncodedString {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
Self::new(s)
}
}
impl core::convert::TryFrom<String> for EncodedString {
type Error = Error;
fn try_from(s: String) -> Result<Self> {
Self::new(s)
}
}
impl<'a> core::convert::TryFrom<&'a str> for EncodedString {
type Error = Error;
fn try_from(s: &'a str) -> Result<Self> {
Self::new(s)
}
}
impl From<EncodedString> for String {
fn from(encoded: EncodedString) -> Self {
encoded.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_valid() {
let encoded = EncodedString::new("zCn8eVZg").unwrap();
assert_eq!(encoded.base(), Base::Base58Btc);
assert_eq!(encoded.as_str(), "zCn8eVZg");
}
#[test]
fn test_new_empty_fails() {
let result = EncodedString::new("");
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::EmptyInput));
}
#[test]
fn test_new_invalid_base_fails() {
let result = EncodedString::new("xInvalid");
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::UnknownBase { .. }));
}
#[test]
fn test_decode() {
let encoded = EncodedString::new("zCn8eVZg").unwrap();
let decoded = encoded.decode().unwrap();
assert_eq!(decoded, b"hello");
}
#[test]
fn test_from_str() {
use core::str::FromStr;
let encoded = EncodedString::from_str("md29ybGQ").unwrap();
assert_eq!(encoded.base(), Base::Base64);
}
#[test]
fn test_try_from_string() {
use core::convert::TryFrom;
let encoded = EncodedString::try_from("f48656c6c6f".to_string()).unwrap();
assert_eq!(encoded.base(), Base::Base16Lower);
}
#[test]
fn test_try_from_str() {
use core::convert::TryFrom;
let encoded = EncodedString::try_from("BPFSXGIDNMFXGSIBB").unwrap();
assert_eq!(encoded.base(), Base::Base32Upper);
}
#[test]
fn test_into_inner() {
let encoded = EncodedString::new("zCn8eVZg").unwrap();
let inner = encoded.into_inner();
assert_eq!(inner, "zCn8eVZg");
}
#[test]
fn test_display() {
let encoded = EncodedString::new("zCn8eVZg").unwrap();
assert_eq!(format!("{}", encoded), "zCn8eVZg");
}
#[test]
fn test_clone() {
let encoded = EncodedString::new("zCn8eVZg").unwrap();
let cloned = encoded.clone();
assert_eq!(encoded, cloned);
}
#[test]
fn test_eq() {
let encoded1 = EncodedString::new("zCn8eVZg").unwrap();
let encoded2 = EncodedString::new("zCn8eVZg").unwrap();
let encoded3 = EncodedString::new("md29ybGQ").unwrap();
assert_eq!(encoded1, encoded2);
assert_ne!(encoded1, encoded3);
}
#[test]
fn test_as_ref() {
let encoded = EncodedString::new("zCn8eVZg").unwrap();
let s: &str = encoded.as_ref();
assert_eq!(s, "zCn8eVZg");
}
}