use base64::engine::GeneralPurpose;
use base64::engine::general_purpose::STANDARD;
use base64::engine::general_purpose::STANDARD_NO_PAD;
use base64::engine::general_purpose::URL_SAFE;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use qubit_codec::CapacityError;
static STANDARD_ENGINE: GeneralPurpose = STANDARD;
static STANDARD_NO_PAD_ENGINE: GeneralPurpose = STANDARD_NO_PAD;
static URL_SAFE_ENGINE: GeneralPurpose = URL_SAFE;
static URL_SAFE_NO_PAD_ENGINE: GeneralPurpose = URL_SAFE_NO_PAD;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Base64Config {
Standard,
StandardNoPad,
UrlSafe,
UrlSafeNoPad,
}
impl Base64Config {
#[inline]
pub(crate) fn engine(self) -> &'static GeneralPurpose {
match self {
Self::Standard => &STANDARD_ENGINE,
Self::StandardNoPad => &STANDARD_NO_PAD_ENGINE,
Self::UrlSafe => &URL_SAFE_ENGINE,
Self::UrlSafeNoPad => &URL_SAFE_NO_PAD_ENGINE,
}
}
#[inline]
pub(crate) fn padded(self) -> bool {
matches!(self, Self::Standard | Self::UrlSafe)
}
}
#[inline]
pub(crate) fn base64_encode_bound(n: usize) -> Result<usize, CapacityError> {
(n / 3)
.checked_add(usize::from(!n.is_multiple_of(3)))
.and_then(|groups| groups.checked_mul(4))
.ok_or(CapacityError::OutputLengthOverflow)
}
#[inline]
pub(crate) fn base64_decode_bound(n: usize) -> Result<usize, CapacityError> {
(n / 4)
.checked_add(usize::from(!n.is_multiple_of(4)))
.and_then(|groups| groups.checked_mul(3))
.ok_or(CapacityError::OutputLengthOverflow)
}