use super::super::config::Base32DecodeConfig;
use super::super::error::Base32Error;
use super::decode_full_groups_into;
use super::decode_tail_into;
#[inline]
pub fn decode_into(
config: &Base32DecodeConfig,
dst: &mut [u8],
src: &[u8],
) -> Result<usize, Base32Error> {
if src.is_empty() {
return Ok(0);
}
let mut padding_count = 0;
if let Some(padding) = config.padding {
for &byte in src.iter().rev().take(7) {
if byte == padding {
padding_count += 1;
} else {
break;
}
}
}
if padding_count > 6 {
return Err(Base32Error::InvalidPadding);
}
let clean_len = src.len() - padding_count;
if clean_len == 0 {
return Ok(0);
}
let output_len = (clean_len * 5) / 8;
if dst.len() < output_len {
return Err(Base32Error::DestinationBufferTooSmall {
needed: output_len,
provided: dst.len(),
});
}
let total_groups = src.len().div_ceil(8);
let full_groups = clean_len / 8;
let has_tail = total_groups > full_groups;
let mut dst_offset = 0usize;
dst_offset += decode_full_groups_into(config, dst, src, full_groups)?;
if has_tail {
let tail_src = &src[full_groups * 8..core::cmp::min(full_groups * 8 + 8, src.len())];
dst_offset += decode_tail_into(
config,
&mut dst[dst_offset..],
tail_src,
full_groups * 8,
padding_count,
)?;
}
Ok(dst_offset)
}