#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{format, string::String, vec::Vec};
#[cfg(feature = "std")]
use std::{format, string::String, vec::Vec};
pub fn hex_to_bytes(s: &str) -> Result<Vec<u8>, String> {
hex::decode(s).map_err(|e| format!("Hex decoding failed for input string '{}': {}", s, e))
}
pub fn bytes_to_hex(b: &[u8]) -> String {
hex::encode(b)
}
pub fn base64_to_bytes(s: &str) -> Result<Vec<u8>, String> {
use base64::{engine::general_purpose::STANDARD, Engine as _};
STANDARD
.decode(s)
.map_err(|e| format!("Base64 decoding failed for input string '{}': {}", s, e))
}
pub fn bytes_to_base64(b: &[u8]) -> String {
use base64::{engine::general_purpose::STANDARD, Engine as _};
STANDARD.encode(b)
}
pub fn base64url_nopad_to_bytes(s: &str) -> Result<Vec<u8>, String> {
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
URL_SAFE_NO_PAD.decode(s).map_err(|e| {
format!(
"Base64 (URL-safe, no pad) decoding failed for '{}': {}",
s, e
)
})
}
pub fn bytes_to_base64url_nopad(b: &[u8]) -> String {
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
URL_SAFE_NO_PAD.encode(b)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hex_conversions() {
let bytes = vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
let hex_string = "0123456789abcdef";
assert_eq!(bytes_to_hex(&bytes), hex_string);
assert_eq!(hex_to_bytes(hex_string).unwrap(), bytes);
assert_eq!(bytes_to_hex(&[]), "");
assert_eq!(hex_to_bytes("").unwrap(), Vec::<u8>::new());
assert!(hex_to_bytes("invalid hex").is_err());
assert!(hex_to_bytes("0g").is_err()); assert!(hex_to_bytes("012").is_err()); }
#[test]
fn test_base64_standard_conversions() {
let original_str = "Hello, dcrypt! This is a test string.";
let bytes = original_str.as_bytes();
let base64_string = "SGVsbG8sIGRjcnlwdCEgVGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg==";
assert_eq!(bytes_to_base64(bytes), base64_string);
assert_eq!(base64_to_bytes(base64_string).unwrap(), bytes);
assert_eq!(bytes_to_base64(&[]), "");
assert_eq!(base64_to_bytes("").unwrap(), Vec::<u8>::new());
assert!(base64_to_bytes("invalid base64 char !@#").is_err());
assert!(
base64_to_bytes("SGVsbG8sIERCWVBUISEgVGhpcyBpcyBhIHRlc3Qgc3RyaW5nLg").is_err(),
"Missing padding should fail strict decode"
);
}
#[test]
fn test_base64url_nopad_conversions() {
let bytes1 = vec![0xfb, 0xfb, 0xff]; let base64url_string1 = "-_v_";
assert_eq!(bytes_to_base64url_nopad(&bytes1), base64url_string1);
assert_eq!(base64url_nopad_to_bytes(base64url_string1).unwrap(), bytes1);
let original_str = "Many hands make light work.";
let bytes = original_str.as_bytes();
let base64url_nopad_string = "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu";
assert_eq!(bytes_to_base64url_nopad(bytes), base64url_nopad_string);
assert_eq!(
base64url_nopad_to_bytes(base64url_nopad_string).unwrap(),
bytes
);
assert_eq!(bytes_to_base64url_nopad(&[]), "");
assert_eq!(base64url_nopad_to_bytes("").unwrap(), Vec::<u8>::new());
assert!(
base64url_nopad_to_bytes("invalid base64 char +/=").is_err(),
"Standard chars should fail URL-safe"
);
}
}