earthbucks_lib 0.8.5

EarthBucks library for data structures and algorithms
Documentation
use crate::error::EbxError;
use bs58;
use hex;
use lazy_static::lazy_static;
use rand::Rng;
use regex::Regex;

lazy_static! {
    static ref RE: Regex = Regex::new(r"^[0-9a-f]*$").unwrap();
}

pub fn is_valid(hex: &str) -> bool {
    RE.is_match(hex) && hex.len() % 2 == 0
}

pub fn encode(data: &[u8]) -> String {
    hex::encode(data)
}

pub fn decode(hex: &str) -> Result<Vec<u8>, EbxError> {
    if !is_valid(hex) {
        return Err(EbxError::InvalidHexError { source: None });
    }
    let res = hex::decode(hex);
    if res.is_err() {
        return Err(EbxError::InvalidHexError { source: None });
    }
    Ok(res.unwrap())
}

pub trait EbxBuf {
    fn to_strict_hex(&self) -> String;
    fn from_strict_hex(hex: &str) -> Result<Self, EbxError>
    where
        Self: Sized;
    fn to_base58(&self) -> String;
    fn from_base58(base58: &str) -> Result<Self, EbxError>
    where
        Self: Sized;
    fn from_random() -> Self;
}

impl EbxBuf for Vec<u8> {
    fn to_strict_hex(&self) -> String {
        hex::encode(self)
    }

    fn from_strict_hex(hex: &str) -> Result<Self, EbxError> {
        hex::decode(hex).map_err(|_| EbxError::InvalidHexError { source: None })
    }

    fn to_base58(&self) -> String {
        bs58::encode(self).into_string()
    }

    fn from_base58(base58: &str) -> Result<Self, EbxError> {
        bs58::decode(base58)
            .into_vec()
            .map_err(|_| EbxError::InvalidEncodingError { source: None })
    }

    fn from_random() -> Self {
        let mut buffer = vec![0u8; 32];
        let mut rng = rand::thread_rng();
        rng.fill(&mut buffer[..]);
        buffer
    }
}

impl<const N: usize> EbxBuf for [u8; N] {
    fn to_strict_hex(&self) -> String {
        hex::encode(self)
    }

    fn from_strict_hex(hex: &str) -> Result<Self, EbxError> {
        let vec = hex::decode(hex).map_err(|_| EbxError::InvalidHexError { source: None })?;
        let array: [u8; N] = vec[..]
            .try_into()
            .map_err(|_| EbxError::InvalidHexError { source: None })?;
        Ok(array)
    }

    fn to_base58(&self) -> String {
        bs58::encode(self).into_string()
    }

    fn from_base58(base58: &str) -> Result<Self, EbxError> {
        let vec = bs58::decode(base58)
            .into_vec()
            .map_err(|_| EbxError::InvalidEncodingError { source: None })?;
        let array: [u8; N] = vec[..]
            .try_into()
            .map_err(|_| EbxError::InvalidEncodingError { source: None })?;
        Ok(array)
    }

    fn from_random() -> Self {
        let mut buffer = [0u8; N];
        let mut rng = rand::thread_rng();
        rng.fill(&mut buffer[..]);
        buffer
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_is_valid() {
        assert!(is_valid("00"));
        assert!(is_valid("1234567890abcdef"));
        assert!(!is_valid("1234567890abcde"));
        assert!(!is_valid("0"));
        assert!(!is_valid("0g"));
        assert!(!is_valid("1234567890abcdeF"));
    }

    #[test]
    fn test_encode_decode() {
        let buffer = hex::decode("1234567890abcdef").unwrap();
        let hex = encode(&buffer);
        let decoded_buffer = decode(&hex).unwrap();
        assert_eq!(decoded_buffer, buffer);
    }
}