use crate::{AppendHexDecode, AppendHexEncode, AsciiCase, Error, FromHexDecode, FromHexEncode};
use vsimd::tools::{alloc_uninit_bytes, assume_init, boxed_str, slice_parts};
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
#[inline]
fn decode_to_boxed_bytes(src: &[u8]) -> Result<Box<[u8]>, Error> {
if src.is_empty() {
return Ok(Box::from([]));
}
ensure!(src.len() % 2 == 0);
unsafe {
let mut buf = alloc_uninit_bytes(src.len() / 2);
{
let (src, len) = slice_parts(src);
let dst: *mut u8 = buf.as_mut_ptr().cast();
crate::multiversion::decode::auto(src, len, dst)?;
}
Ok(assume_init(buf))
}
}
#[inline]
fn decode_append_vec(src: &[u8], buf: &mut Vec<u8>) -> Result<(), Error> {
if src.is_empty() {
return Ok(());
}
ensure!(src.len() % 2 == 0);
let m = src.len() / 2;
buf.reserve_exact(m);
let prev_len = buf.len();
unsafe {
let (src, len) = slice_parts(src);
let dst = buf.as_mut_ptr().add(prev_len);
crate::multiversion::decode::auto(src, len, dst)?;
buf.set_len(prev_len + m);
Ok(())
}
}
#[inline]
fn encode_to_boxed_str(src: &[u8], case: AsciiCase) -> Box<str> {
if src.is_empty() {
return Box::from("");
}
unsafe {
let m = src.len() * 2;
assert!(m <= usize::MAX / 2);
let mut buf = alloc_uninit_bytes(m);
{
let (src, len) = slice_parts(src);
let dst: *mut u8 = buf.as_mut_ptr().cast();
crate::multiversion::encode::auto(src, len, dst, case);
}
boxed_str(assume_init(buf))
}
}
#[inline]
fn encode_append_vec(src: &[u8], buf: &mut Vec<u8>, case: AsciiCase) {
if src.is_empty() {
return;
}
unsafe {
let m = src.len() * 2;
assert!(m <= usize::MAX / 2);
buf.reserve_exact(m);
let prev_len = buf.len();
let (src, len) = slice_parts(src);
let dst = buf.as_mut_ptr().add(prev_len);
crate::multiversion::encode::auto(src, len, dst, case);
buf.set_len(prev_len + m);
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl FromHexDecode for Box<[u8]> {
#[inline]
fn from_hex_decode(data: &[u8]) -> Result<Self, Error> {
decode_to_boxed_bytes(data)
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl FromHexDecode for Vec<u8> {
#[inline]
fn from_hex_decode(data: &[u8]) -> Result<Self, Error> {
let ans = decode_to_boxed_bytes(data)?;
Ok(Vec::from(ans))
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl FromHexEncode for Box<[u8]> {
#[inline]
#[must_use]
fn from_hex_encode(data: &[u8], case: AsciiCase) -> Self {
let ans = encode_to_boxed_str(data, case);
ans.into_boxed_bytes()
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl FromHexEncode for Box<str> {
#[inline]
#[must_use]
fn from_hex_encode(data: &[u8], case: AsciiCase) -> Self {
encode_to_boxed_str(data, case)
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl FromHexEncode for Vec<u8> {
#[inline]
#[must_use]
fn from_hex_encode(data: &[u8], case: AsciiCase) -> Self {
let ans = encode_to_boxed_str(data, case);
Vec::from(ans.into_boxed_bytes())
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl FromHexEncode for String {
#[inline]
#[must_use]
fn from_hex_encode(data: &[u8], case: AsciiCase) -> Self {
let ans = encode_to_boxed_str(data, case);
String::from(ans)
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl AppendHexEncode for Vec<u8> {
#[inline]
fn append_hex_encode(src: &[u8], dst: &mut Self, case: AsciiCase) {
encode_append_vec(src, dst, case);
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl AppendHexEncode for String {
#[inline]
fn append_hex_encode(src: &[u8], dst: &mut Self, case: AsciiCase) {
unsafe { encode_append_vec(src, dst.as_mut_vec(), case) }
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl AppendHexDecode for Vec<u8> {
#[inline]
fn append_hex_decode(src: &[u8], dst: &mut Self) -> Result<(), Error> {
decode_append_vec(src, dst)
}
}